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