Разработка и Конфигурация · 8 мин
Как изменить реквизит документа программно в 1С
Как программно изменить реквизит документа в 1С: объектная модель, ПолучитьОбъект, запись, типовые ошибки, транзакции и проверка результата.
Изменение реквизита документа программно — одна из базовых задач при доработке конфигураций 1С: исправление данных обработкой, автозаполнение полей при записи, интеграция с внешними системами. Ключевой принцип один: нельзя изменить реквизит через ссылку на документ напрямую — нужно получить объект документа, изменить его свойства и записать. Попытка присвоить значение через ссылку приведёт к ошибке «Поле объекта не обнаружено» или просто не сработает.
Ниже разобраны основные способы: через метод ПолучитьОбъект(), через функции работы с формами, через запросы с последующей записью, а также особенности изменения проведённых документов, табличных частей и типовых реквизитов типовых конфигураций. Примеры кода приведены для встроенного языка 1С:Предприятие 8.3 и подходят как для обычных, так и для управляемых форм.
Базовый способ: ПолучитьОбъект и Записать
Стандартная последовательность состоит из трёх шагов. Сначала у вас есть ссылка на документ (из выборки запроса, параметра обработки или формы списка). Затем вы получаете объект — полную копию данных документа в памяти. После изменения реквизитов объект записывается обратно в базу.
ДокументОбъект = ДокументСсылка.ПолучитьОбъект();
ДокументОбъект.Комментарий = "Изменено обработкой";
ДокументОбъект.Ответственный = ПараметрыСеанса.ТекущийПользователь;
ДокументОбъект.Записать();
Метод Записать() без параметров сохраняет документ в текущем режиме: если документ был проведён — попытается провести, если нет — просто запишет. Чтобы записать без проведения, используйте Записать(РежимЗаписиДокумента.Запись), а для проведения — Записать(РежимЗаписиДокумента.Проведение). Обратите внимание: ПолучитьОбъект() блокирует документ, поэтому в цикле обработки многих документов объекты следует записывать и освобождать сразу, не накапливая их.
ДокументОбъект = ДокументСсылка.ПолучитьОбъект();
ДокументОбъект.Склад = НовыйСклад;
ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);Изменение табличной части документа
Табличные части меняются через тот же объект документа. Можно перебрать строки и изменить значения в нужных, добавить новую строку методом Добавить() или очистить всю табличную часть методом Очистить(). Все изменения вступят в силу только после Записать() объекта.
ДокументОбъект = ДокументСсылка.ПолучитьОбъект();
Для Каждого СтрокаТовара Из ДокументОбъект.Товары Цикл
СтрокаТовара.Цена = СтрокаТовара.Цена * 1.1;
КонецЦикла;
ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);
Если нужно изменить только одну строку, ищите её по ключевому полю (номенклатура, характеристика) через Найти() или перебором с условием. Помните, что при пересчёте цен и сумм в типовых документах не срабатывают обработчики формы (например, пересчёт суммы от цены и количества) — эту логику нужно воспроизводить в коде самостоятельно.
Особенности изменения проведённых документов
Для проведённого документа есть два варианта. Первый — записать с режимом Запись: реквизиты изменятся, движения по регистрам останутся прежними. Это уместно для «неучётных» полей вроде комментария или ответственного. Второй — перепровести документ: тогда движения будут пересчитаны с учётом новых значений реквизитов.
Если изменённый реквизит участвует в проведении (склад, контрагент, валюта), запись без перепроведения создаст расхождение между данными документа и регистрами — это типичный источник ошибок в отчётах. Перед массовым изменением таких реквизитов проанализируйте модуль проведения документа и решите, требуется ли перепроведение.
Изменение реквизита без получения объекта: когда это возможно
Через ссылку реквизиты доступны только для чтения: ДокументСсылка.Номер вернёт значение, но присвоить его нельзя. Исключение — прямое обновление через запрос с конструкцией ИЗМЕНИТЬ, однако встроенный язык 1С такой возможности для таблиц документов не предоставляет в штатном режиме; обходные пути через внешние компоненты и прямой SQL нарушают логику платформы и поддерживаемы не будут.
Легитимная альтернатива — установка значений через менеджер документа при создании нового документа: Документы.РеализацияТоваровУслуг.СоздатьДокумент() сразу возвращает объект, и заполнение реквизитов до первой записи — самый быстрый сценарий. Для существующих документов ПолучитьОбъект() остаётся единственным корректным путём.
Транзакции и обработка ошибок при записи
При массовом изменении реквизитов разумно оборачивать запись в транзакцию и обработку исключений. Если один документ не записался (заблокирован другим пользователем, не прошёл контроль проведения), цикл не должен прерываться — ошибку фиксируют и продолжают обработку.
Для Каждого СтрокаВыборки Из Выборка Цикл
Попытка
ДокументОбъект = СтрокаВыборки.Ссылка.ПолучитьОбъект();
ДокументОбъект.Комментарий = НовыйКомментарий;
ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);
Исключение
Сообщить("Не удалось изменить " + СтрокаВыборки.Ссылка
+ ": " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
Если требуется принцип «все или ничего», весь цикл помещается между НачатьТранзакцию() и ЗафиксироватьТранзакцию(), а в блоке Исключение вызывается ОтменитьТранзакцию(). Учтите, что длинная транзакция держит блокировки и может мешать работе пользователей — для больших объёмов надёжнее пакетная обработка с фиксацией каждые несколько сотен документов.
- 1Сделайте резервную копию базы или протестируйте обработку на копии
- 2Сформируйте запросом список ссылок на документы для изменения
- 3В цикле получайте объект, меняйте реквизит, записывайте в нужном режиме
- 4Оборачивайте запись в Попытка/Исключение и собирайте протокол ошибок
- 5Проверьте результат на выборке документов и в связанных отчётах
Проверка результата и типовые ошибки
После записи убедитесь, что изменения применились: откройте документ в пользовательском режиме или выполните контрольный запрос по изменённому реквизиту. Если документ проводится, дополнительно проверьте движения — через отчёт «Движения документа» или запрос к регистрам.
Частые ошибки при программном изменении реквизитов: попытка присвоить значение через ссылку (ошибка времени выполнения), запись проведённого документа без указания режима (неожиданное перепроведение и изменение движений), игнорирование обязательных для заполнения реквизитов (отказ записи с сообщением контроля), а также изменение документов в закрытом периоде, когда дата запрета редактирования блокирует запись.
FAQ: частые вопросы
Можно ли изменить реквизит документа, не открывая транзакцию записи объекта?
Нет, штатного способа точечного обновления одного поля встроенный язык не предоставляет. Любое изменение проходит через получение объекта и Записать(). Прямые обращения к СУБД минуют механизмы платформы, ломают версионирование и кэш и считаются недопустимой практикой.
Как изменить реквизит у помеченного на удаление документа?
Технически так же — через ПолучитьОбъект() и Записать(). Но сначала решите, зачем это нужно: обычно корректнее снять пометку удаления методом УстановитьПометкуУдаления(Ложь), изменить данные и затем работать с документом как с обычным.
Почему после изменения цены в табличной части сумма не пересчиталась?
Пересчёт суммы в типовых документах выполняется в обработчиках формы клиента, которые при программном изменении объекта не вызываются. Пересчитайте сумму в коде самостоятельно или вызовите соответствующую экспортную процедуру из общего модуля обработки табличных частей, если она есть в конфигурации.
Как изменить реквизит у документов за закрытый период?
Нужно временно сдвинуть дату запрета редактирования для пользователя или группы, выполнить изменения и вернуть дату обратно. Делать это следует осознанно: изменение документов закрытого периода может потребовать корректировки отчётности и перепроведения зависимых документов.
Чем отличается ОбменДанными.Загрузка = Истина при записи?
Этот режим отключает проверки заполнения и бизнес-логику подписок на события записи. Он предназначен для загрузки данных из обменов. Использовать его для обычного изменения реквизитов опасно: документ запишется без контроля, но может оказаться в неконсистентном состоянии.
Что важно запомнить
Реквизит документа меняется только через объект: ПолучитьОбъект() → присвоение → Записать() с явным режимом. Для проведённых документов решайте, нужно ли перепроведение, при массовых изменениях используйте обработку ошибок и предварительно делайте копию базы.