К статье
Практический материал

Разработка и Конфигурация · 10 мин

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

Как программно добавить строку в табличную часть документа 1С: методы Добавить(), Записать(), работа с объектом и ссылкой, примеры кода и типичные ошибки.

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

Работа с табличной частью всегда идёт через объект документа, а не через ссылку. Ссылка — только идентификатор записи в базе, изменять данные через неё нельзя. Поэтому типовой сценарий выглядит так: получаем объект методом ПолучитьОбъект(), добавляем или изменяем строки коллекции, затем вызываем Записать().

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

Получение объекта документа — обязательный первый шаг

Любые изменения данных документа выполняются только через объект. Если у вас есть ссылка на документ (например, она пришла параметром в обработку или найдена запросом), сначала получите объект:

ДокОбъект = ДокументСсылка.ПолучитьОбъект();

Если документ создаётся новый, объект получают через менеджер документа:

ДокОбъект = Документы.РеализацияТоваровУслуг.СоздатьДокумент();

ДокОбъект.Дата = ТекущаяДатаСеанса();

ДокОбъект.Контрагент = КонтрагентСсылка;

Важно понимать разницу: ДокументСсылка.Товары — это тоже доступ к табличной части, но только для чтения. Попытка вызвать Добавить() у такой коллекции не изменит данные в базе, а в ряде контекстов приведёт к ошибке. Меняем всегда коллекцию объекта.

Добавление новой строки в табличную часть

Основной метод — Добавить(). Он возвращает новую строку коллекции, реквизиты которой заполняются через точку:

НоваяСтрока = ДокОбъект.Товары.Добавить();

НоваяСтрока.Номенклатура = НоменклатураСсылка;

НоваяСтрока.Количество = 5;

НоваяСтрока.Цена = 1200;

НоваяСтрока.Сумма = НоваяСтрока.Количество * НоваяСтрока.Цена;

Обратите внимание: платформа не пересчитывает суммы автоматически — это делает код конфигурации (обычно в обработчиках формы или модуле объекта). Если вы заполняете строку программно, расчёт суммы, НДС и итогов лежит на вас. В типовых конфигурациях часто есть экспортные процедуры вида РассчитатьСуммуСтроки() в общих модулях — используйте их, чтобы не дублировать логику.

Для заполнения строки по образцу удобен метод Заполнить() у строки или копирование структурой. Если нужно добавить строку в конкретную позицию, используйте Вставить(Индекс) вместо Добавить().

bsl
ДокОбъект = ДокументСсылка.ПолучитьОбъект();
НоваяСтрока = ДокОбъект.Товары.Добавить();
НоваяСтрока.Номенклатура = НоменклатураСсылка;
НоваяСтрока.Количество = 5;
НоваяСтрока.Цена = 1200;
НоваяСтрока.Сумма = НоваяСтрока.Количество * НоваяСтрока.Цена;
ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);

Изменение и поиск существующих строк

Чтобы изменить уже записанную строку, её сначала нужно найти. Для перебора всех строк используйте цикл:

Для Каждого СтрокаТовара Из ДокОбъект.Товары Цикл

Если СтрокаТовара.Номенклатура = ИскомаяНоменклатура Тогда

СтрокаТовара.Количество = СтрокаТовара.Количество + 1;

КонецЕсли;

КонецЦикла;

Для точечного поиска эффективнее метод Найти(Значение, ИмяКолонки) — он возвращает первую найденную строку или Неопределено. Метод НайтиСтроки(ПараметрыОтбора) возвращает массив всех подходящих строк и удобен, когда совпадений несколько:

ПараметрыОтбора = Новый Структура("Номенклатура", НоменклатураСсылка);

НайденныеСтроки = ДокОбъект.Товары.НайтиСтроки(ПараметрыОтбора);

Для Каждого Строка Из НайденныеСтроки Цикл

Строка.Цена = НоваяЦена;

КонецЦикла;

Удаление строк выполняется методом Удалить(Строка) или Удалить(Индекс). При удалении в цикле перебирайте коллекцию с конца или используйте массив, полученный через НайтиСтроки() — иначе индексы сместятся и часть строк будет пропущена.

Очистка табличной части и массовое заполнение

Полная очистка выполняется одним вызовом:

ДокОбъект.Товары.Очистить();

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

Запрос = Новый Запрос;

Запрос.Текст = "ВЫБРАТЬ Номенклатура, Количество ИЗ ...";

ДокОбъект.Товары.Загрузить(Запрос.Выполнить().Выгрузить());

Если нужно не заменить, а дополнить табличную часть, используйте цикл по таблице значений с Добавить() и ЗаполнитьЗначенияСвойств() для копирования совпадающих по именам колонок.

Способы заполнения табличной части

Добавить() в цикле

Гибкий контроль каждой строки, подходит для сложной логики расчёта. Медленнее при больших объёмах.

Загрузить(ТЗ)

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

НайтиСтроки() + изменение

Точечное обновление нужных строк без затрагивания остальных.

Запись документа: режимы и проверка результата

После изменения табличной части объект нужно записать. Метод Записать() без параметров сохраняет документ в режиме записи, Записать(РежимЗаписиДокумента.Проведение) — сразу проводит его, Записать(РежимЗаписиДокумента.ОтменаПроведения) — отменяет проведение.

Если документ проводится, учтите: при проведении могут сработать контроли остатков, заполненности реквизитов и другие проверки в модуле объекта. Ошибка проведения отменит и запись табличной части. Поэтому программную запись стоит оборачивать в попытку с обработкой исключения:

Попытка

ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);

Исключение

Сообщить("Ошибка записи: " + ОписаниеОшибки());

КонецПопытки;

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

Контрольные точки

Как проверить результат

Открыть документ в режиме 1С:Предприятие
Норма

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

Тревожный признак

Строк нет — значит, Записать() не вызван или завершился ошибкой

Провести документ вручную
Норма

Проводится без сообщений об ошибках

Тревожный признак

Ошибки контроля остатков или незаполненных реквизитов строки

Движения документа по регистрам
Норма

Движения соответствуют добавленным строкам

Тревожный признак

Движения не изменились — документ записан без проведения

Типичные ошибки и ограничения

Самая распространённая ошибка — забыть вызвать Записать(). Код отрабатывает без сообщений, строки добавляются в коллекцию объекта в памяти, но в базе ничего не меняется. Вторая по частоте — попытка изменить табличную часть через ссылку либо работа с объектом, который уже открыт пользователем в форме: тогда при записи возникнет конфликт блокировок.

Отдельная группа проблем — обход бизнес-логики конфигурации. При интерактивном вводе строки в форме срабатывают обработчики «ПриИзменении», которые подставляют цены, ставки НДС, счета учёта, единицы измерения. Программное добавление строки эти обработчики не вызывает. Если не заполнить такие реквизиты явно, документ запишется с пустыми полями и может не провестись или даст неверные движения.

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

Типичные ошибки
01
Изменение коллекции без вызова Записать() — данные остаются только в памяти и теряются
02
Заполнение только номенклатуры и количества без цен, ставок НДС и счетов учёта — документ не проводится или даёт неверные движения
03
Удаление строк в прямом цикле перебора — смещение индексов и пропуск строк
04
Длительная работа между ПолучитьОбъект() и Записать() — блокировка документа для других пользователей

Частые вопросы

Можно ли добавить строку в табличную часть, не открывая объект документа?

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

Почему строки добавляются, но после закрытия обработки пропадают?

Почти всегда причина в отсутствии вызова Записать() у объекта документа. Коллекция табличной части существует в памяти, и пока объект не записан, изменения в базу не попадают. Также проверьте, не завершается ли Записать() исключением, которое перехватывается пустым обработчиком.

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

Программное добавление не вызывает обработчики формы «ПриИзменении». Найдите в конфигурации общий модуль, где реализован расчёт строки (в типовых это часто процедуры вида РассчитатьСуммуВСтрокеТЧ или аналогичные), и вызовите его для добавленной строки, либо воспроизведите расчёт в своём коде.

Чем отличается Загрузить() от добавления строк в цикле?

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

Документ проведён. Нужно ли отменять проведение перед изменением табличной части?

Не обязательно: объект проведённого документа можно изменить и записать. Но движения по регистрам при этом не обновятся автоматически — после изменения документ нужно перепровести, иначе данные табличной части и учётные регистры разойдутся.

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

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

Итог

Что важно запомнить

Запись в табличную часть документа всегда идёт по схеме: ПолучитьОбъект() → Добавить()/изменение строк → заполнение всех нужных реквизитов, включая суммы и учётные поля → Записать() с нужным режимом. Тестируйте код на копии базы и помните, что программное добавление строк не запускает обработчики формы.