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