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

Программист 1С v8.3 (Обычные формы)
← На главную

При разработке внешних обработок для массового изменения данных в 1С начинающие программисты часто сталкиваются с ситуацией, когда написанный код либо вызывает синтаксические ошибки, либо отрабатывает без видимых ошибок, но физически данные в документах не меняются. Особенно много вопросов вызывает работа с табличными частями (ТЧ) документов, такими как список товаров, услуг или работ.

В этой статье мы подробно разберем практический кейс с форума, посвященный изменению коэффициента в табличной части Работы документа Заказ-наряд (на примере отраслевого решения «Альфа-Авто»). Мы проанализируем типичные ошибки разработчиков, выясним причины их возникновения и напишем правильный, оптимизированный алгоритм решения задачи.

Анализ типичных ошибок начинающего разработчика

Рассмотрим исходный код, с которым автор темы обратился на форум:


Пока Выборка.Следующий() Цикл 
    Объект = Выборка.Ссылка.ПолучитьОбъект();
    Если Выборка.Коэффициент = "0,200" Тогда
        Объект.Коэффициент = "1,200";
    КонецЕсли;
    Попытка
        Объект.Записать();
        Сообщить(Выборка.Ссылка)
    Исключение
        Сообщить("НормЧасы " + Выборка.Ссылка + " не изменены.");
    КонецПопытки;
КонецЦикла;

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

Ошибка №1: Несоответствие типов при сравнении (Строка vs Число)

Обратим внимание на условие: Если Выборка.Коэффициент = "0,200" Тогда. В базе данных реквизит Коэффициент имеет тип Число. Автор пытается сравнить его со строковым литералом "0,200".

В платформе 1С:Предприятие при сравнении значений разных типов автоматическое (неявное) преобразование типов для логических операций не выполняется. Число никогда не будет равно строке. Следовательно, это условие всегда возвращает значение Ложь, код внутри условия игнорируется, и изменения не вносятся. Для исправления этой ошибки необходимо сравнивать число с числом: Если Выборка.Коэффициент = 0.2 Тогда.

Ошибка №2: Использование неверного разделителя дробной части

В процессе исправления кода автор допустил следующую ошибку в синтаксисе языка 1С:

Объект.Коэффициент = 1,200;

Попытка использовать запятую в качестве разделителя дробной части приводит к синтаксической ошибке компилятора: Неопознанный оператор... Ожидается ключевое слово 'КонецЦикла'. В языке программирования 1С единственным допустимым разделителем дробной части для числовых литералов является точка (.). Правильная запись выглядит так: 1.2 или 1.200.

Ошибка №3: Обращение к реквизиту табличной части через шапку объекта

Самая главная архитектурная ошибка кроется в строке: Объект.Коэффициент = 1.2;. Она вызывает ошибку времени выполнения: Поле объекта не обнаружено (Коэффициент).

Дело в том, что Коэффициент — это реквизит табличной части Работы, а не шапки документа Заказ-наряд. Мы не можем обратиться к нему напрямую через точку от объекта документа. Нам необходимо сначала обратиться к самой табличной части, найти нужную строку (или обойти все строки в цикле) и только потом изменить реквизит в конкретной строке.

---

Пошаговый алгоритм решения задачи

Для того чтобы правильно и быстро изменить значение в табличной части документа, выполним несколько последовательных шагов.

Шаг 1. Оптимизация запроса

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

Правильный подход — выбрать запросом только уникальные ссылки документов, которые требуют изменения, используя ключевое слово РАЗЛИЧНЫЕ.

Шаг 2. Обход строк табличной части объекта

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

Шаг 3. Установка флага модифицированности

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

---

Готовое решение: исправленный и оптимизированный код

Проанализируем готовый шаблон кода внешней обработки, который решает поставленную задачу эффективно и безопасно:


Процедура КнопкаВыполнитьНажатие(Кнопка)
    
    // Шаг 1. Находим искомую работу по коду в справочнике
    РаботаСсылка = Справочники.Автоработы.НайтиПоКоду("ЦБ00021506");
    Если НЕ ЗначениеЗаполнено(РаботаСсылка) Тогда
        Сообщить("Внимание! Работа с кодом ЦБ00021506 не найдена в справочнике.");
        Возврат;
    КонецЕсли;
    
    // Шаг 2. Запрос для выбора уникальных ссылок на документы
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ РАЗЛИЧНЫЕ
        |	ЗаказНарядРаботы.Ссылка КАК Ссылка
        |ИЗ
        |	Документ.ЗаказНаряд.Работы КАК ЗаказНарядРаботы
        |ГДЕ
        |	ЗаказНарядРаботы.Работа = &Работа
        |	И ЗаказНарядРаботы.Коэффициент = &СтарыйКоэффициент";
    
    Запрос.УстановитьПараметр("Работа", РаботаСсылка);
    // Сравниваем числовые значения, используя правильный тип (Число)
    Запрос.УстановитьПараметр("СтарыйКоэффициент", 0.2); 
    
    РезультатЗапроса = Запрос.Выполнить();
    Если РезультатЗапроса.Пустой() Тогда
        Сообщить("Документы для обработки не найдены.");
        Возврат;
    КонецЕсли;
    
    Выборка = РезультатЗапроса.Выбрать();
    
    // Шаг 3. Обход документов и изменение реквизитов ТЧ
    Пока Выборка.Следующий() Цикл
        
        ДокОбъект = Выборка.Ссылка.ПолучитьОбъект();
        ДокументМодифицирован = Ложь;
        
        // Перебираем строки табличной части "Работы"
        Для Каждого СтрокаРаботы Из ДокОбъект.Работы Цикл
            
            // Проверяем условия для конкретной строки
            Если СтрокаРаботы.Работа = РаботаСсылка И СтрокаРаботы.Коэффициент = 0.2 Тогда
                
                // Присваиваем новое числовое значение
                СтрокаРаботы.Коэффициент = 1.2; 
                ДокументМодифицирован = Истина;
                
            КонецЕсли;
            
        КонецЦикла;
        
        // Записываем документ только при наличии изменений
        Если ДокументМодифицирован Тогда
            Попытка
                // Режим записи выбирается в зависимости от бизнес-логики (Запись или Проведение)
                ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
                Сообщить("Документ " + Выборка.Ссылка + " успешно обработан.");
            Исключение
                Сообщить("Ошибка записи документа " + Выборка.Ссылка + "! Описание: " + КраткоеОписаниеОшибки(ИнформацияОбОшибке()));
            КонецПопытки;
        КонецЕсли;
        
    КонецЦикла;
    
    Сообщить("Обработка завершена.");
    
КонецПроцедуры

---

Важные особенности работы с заказ-нарядами (на примере «Альфа-Авто»)

При работе с комплексными отраслевыми решениями, такими как «Альфа-Авто» от компании «1С-Рарус», простого изменения коэффициента в строке табличной части часто бывает недостаточно. Рассмотрим важные нюансы, которые необходимо учитывать:

  1. Пересчет суммовых показателей строки. В конфигурациях автосервиса коэффициент напрямую влияет на калькуляцию строки: Всего = Количество * Цена * Коэффициент. Если программно изменить только коэффициент и записать документ, то итоговая сумма строки останется старой. Это приведет к нарушению математической логики документа.
    Решение: После изменения коэффициента в коде необходимо вызвать специализированную процедуру пересчета строки из общего модуля конфигурации. Например: РаботаАвтосервис.РассчитатьСуммуСтроки(СтрокаРаботы, ДокОбъект); (имя модуля и процедуры может отличаться в зависимости от редакции вашей конфигурации).
  2. Статусы документов и проведение. Документы Заказ-наряд в процессе жизненного цикла меняют свои статусы («Заявка», «В работе», «Выполнен», «Закрыт»). Если документ уже закрыт и проведен, простая запись объекта в режиме РежимЗаписиДокумента.Запись может привести к расхождениям между данными в документе и движениями в регистрах накопления (взаиморасчеты, выработка мастеров и т.д.).
    Решение: Для проведенных документов необходимо выполнять запись в режиме проведения: ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);, предварительно убедившись, что период не закрыт для редактирования.

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

← На главную