При доработке алгоритмов проведения документов (например, СписаниеТоваров) часто возникает задача выполнить дополнительные движения по регистрам только при наличии определенного счета учета затрат. Начинающие разработчики нередко сталкиваются с ошибками вида «Поле объекта не обнаружено» при попытке обратиться к реквизиту табличной части напрямую через коллекцию.
Разберем подробно, почему возникают такие ошибки и как правильно организовать проверку счета учета для строк табличной части документа.
Выясним причину, по которой код разработчика вызывает исключения. Рассмотрим ошибочные конструкции, которые часто пишутся интуитивно:
// Ошибка: Поле объекта не обнаружено (Колонки)
Если ЭтотОбъект.Товары.Колонки.СчетУчетаБУ.Код = 2410 Тогда
Коллекция Колонки существует у объекта ТаблицаЗначений, но отсутствует у объекта ТабличнаяЧасть. Кроме того, даже в таблице значений коллекция колонок описывает метаданные (имя, тип), а не содержит конкретные данные строк.
// Ошибка: Поле объекта не обнаружено (СчетУчетаБУ)
Если ЭтотОбъект.Товары.СчетУчетаБУ.Код = 2410 Тогда
Объект ТабличнаяЧасть представляет собой коллекцию строк. У самой коллекции нет реквизитов строк (таких как СчетЗатратБУ или Номенклатура) — они принадлежат отдельным строкам коллекции.
// Ошибка: Поле объекта не обнаружено (Индекс)
Если ЭтотОбъект.Товары.Индекс[0].СчетЗатратБУ = 2410 Тогда
В платформе 1С получение элемента по индексу выполняется с помощью квадратных скобок непосредственно у самой коллекции: Товары[0].
Если требуется проверить значение в строго определенной строке (например, в первой), обратимся к строке по индексу 0. При этом обязательно проверим, что табличная часть не пуста, чтобы не получить исключение «Индекс находится за границами диапазона».
Посмотрим на пример безопасного кода:
Если ЭтотОбъект.Товары.Количество() > 0 Тогда
СтрокаТЧ = ЭтотОбъект.Товары[0];
// Сравнение кода счета в виде строки
Если СтрокаТЧ.СчетЗатратБУ.Код = "2410" Тогда
// Выполняем алгоритм формирования движений
КонецЕсли;
КонецЕсли;
В реальной практике в документе может быть несколько строк, и у каждой строки может быть указан свой счет затрат. Если вынести условие наружу всей процедуры, движения по регистру сформируются либо для всех строк (если первая строка подошла), либо не сформируются вовсе.
Поэтому правильным архитектурным решением является перенос проверки внутрь цикла Для Каждого. Проанализируем реализацию:
// Получаем предопределенный счет заранее, чтобы не делать лишних запросов в цикле
СчетОС = ПланыСчетов.Типовой.НайтиПоКоду("2410");
ОперацииОС = Движения.СобытияОСОрганизаций;
ПараметрыАмортизацииОС = Движения.ПараметрыАмортизацииОСБухгалтерскийУчет;
Для Каждого СтрокаТЧ Из Товары Цикл
// Проверяем счет учета текущей строки
Если СтрокаТЧ.СчетЗатратБУ = СчетОС Тогда
ТекОС = СтрокаТЧ.СубконтоЗатратБУ1;
// Формируем движения по регистрам ОС
Движение = ОперацииОС.Добавить();
Движение.Период = Дата;
Движение.ОсновноеСредство = ТекОС;
Движение.Организация = СтруктураШапкиДокумента.Организация;
Движение.СтруктурноеПодразделение = СтруктураШапкиДокумента.СтруктурноеПодразделение;
Движение.Событие = СтруктураШапкиДокумента.СобытиеОС;
Движение.НазваниеДокумента = Строка(Метаданные());
Движение.НомерДокумента = Номер;
ДвижениеАм = ПараметрыАмортизацииОС.Добавить();
ДвижениеАм.Период = Дата;
ДвижениеАм.ОсновноеСредство = ТекОС;
ДвижениеАм.Организация = СтруктураШапкиДокумента.Организация;
ДвижениеАм.СтруктурноеПодразделение = СтруктураШапкиДокумента.СтруктурноеПодразделение;
ДвижениеАм.СрокПолезногоИспользования = СтрокаТЧ.СрокПолезногоИспользованияБУ;
ДвижениеАм.СтоимостьДляВычисленияАмортизации = СтрокаТЧ.СтоимостьБУ + (СтрокаТЧ.СуммаМодернизацииБУ * СтрокаТЧ.Количество);
КонецЕсли;
КонецЦикла;
Если требуется быстро отобрать только строки с нужным счетом без ручной фильтрации внутри основного цикла, воспользуемся методом НайтиСтроки():
СчетОС = ПланыСчетов.Типовой.НайтиПоКоду("2410");
ПараметрыОтбора = Новый Структура;
ПараметрыОтбора.Вставить("СчетЗатратБУ", СчетОС);
МассивСтрокОС = Товары.НайтиСтроки(ПараметрыОтбора);
Для Каждого СтрокаТЧ Из МассивСтрокОС Цикл
// Обработка строк, в которых счет затрат равен 2410
КонецЦикла;
СтрокаТЧ.СчетЗатратБУ.Код = "2410" выполняет неявное обращение к базе данных через точку для каждой строки. Рекомендуется один раз получить ссылку на счет (через ПланыСчетов.Типовой... или метод НайтиПоКоду до цикла) и сравнивать ссылки напрямую.СтрокаТЧ.СчетЗатратБУ.ПринадлежитЭлементу(СчетОС) или ВПодчинении().СубконтоЗатратБУ1 имеет составной тип. Перед заполнением специализированных регистров внеоборотных активов убедитесь, что в субконто действительно передан элемент нужного справочника:
Если ЗначениеЗаполнено(ТекОС) И ТипЗнч(ТекОС) = Тип("СправочникСсылка.ОсновныеСредства") Тогда
// Запись в регистры ОС
КонецЕсли;