Как записать данные в проведенный документ без изменения движений по регистрам

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

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

Различие между проведением и простой записью документа

Для начала проанализируем механику работы платформы 1С. Когда мы работаем с документом, у нас есть несколько режимов записи, определяемых перечислением РежимЗаписиДокумента:

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

Если наша цель — только заполнить колонки табличной части "Цена" и "Сумма", нам необходим именно режим РежимЗаписиДокумента.Запись.

Разбор типичной ошибки: Метод формы vs Метод объекта

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

Если вы вызываете метод Записать() у формы, он ожидает в качестве параметра структуру. Синтаксис выглядит так:


ПараметрыЗаписи = Новый Структура;
ПараметрыЗаписи.Вставить("РежимЗаписи", РежимЗаписиДокумента.Запись);
Записать(ПараметрыЗаписи);

Если же вы работаете на стороне сервера с самим объектом (например, получили его через Ссылка.ПолучитьОбъект()), то синтаксис будет иным:


ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();
// Заполняем нужные данные
Для Каждого СтрокаТЧ Из ДокументОбъект.Товары Цикл
    СтрокаТЧ.ол_РозничнаяЦена = ПолучитьЦену(СтрокаТЧ.Номенклатура);
    СтрокаТЧ.ол_Сумма = СтрокаТЧ.Количество * СтрокаТЧ.ол_РозничнаяЦена;
КонецЦикла;
// Записываем объект строго в режиме записи
ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);

Использование свойства ОбменДанными.Загрузка

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

Для обхода этих ограничений (при наличии соответствующих прав у пользователя или выполнении кода в привилегированном модуле) используется важнейшее свойство ОбменДанными.Загрузка. Рассмотрим пример:


ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();
ДокументОбъект.ОбменДанными.Загрузка = Истина;
// Заполнение данных табличной части
// ...
ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);

Важный момент: установка флага Загрузка = Истина отключает выполнение большинства проверок в модуле объекта. Это гарантирует, что документ запишется "как есть", без анализа корректности других реквизитов и без попыток изменить движения.

Почему заполнение "при открытии" — это плохая практика?

Выясним, почему логика автора вопроса (заполнять при открытии формы) является неудачной. Представьте ситуацию: пользователь открывает документ десятилетней давности просто для просмотра. Программа автоматически модифицирует объект и пытается его записать. Это приводит к следующим проблемам:

  1. Блокировки: Если одновременно несколько пользователей или фоновых процессов попытаются проделать то же самое, возникнут конфликты блокировок.
  2. Производительность: Открытие формы замедляется, так как системе нужно выполнить расчеты и транзакцию записи.
  3. Права доступа: У рядового бухгалтера может быть право на просмотр старых документов, но не на их изменение. В итоге он увидит ошибку "Доступ запрещен" при каждой попытке открыть документ.

Вместо этого рекомендуется использовать обработки группового изменения реквизитов или специальные регламентные задания.

Рекомендуемый алгоритм: Групповое заполнение

Вместо изменения кода формы, создадим небольшую процедуру, которую можно запустить один раз или вызывать порциями. Проанализируем пример кода для фонового заполнения:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   ПеремещениеТоваров.Ссылка КАК Ссылка
    |ИЗ
    |   Документ.ПеремещениеТоваров КАК ПеремещениеТоваров
    |ГДЕ
    |   ПеремещениеТоваров.Проведен = ИСТИНА
    |   И ПеремещениеТоваров.Товары.ол_РозничнаяЦена = 0";

Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();

Пока Выборка.Следующий() Цикл
    Объект = Выборка.Ссылка.ПолучитьОбъект();
    // Логика заполнения цен
    ол_ЗаполнениеРозничныхЦен.Заполнить(Объект); 
    
    // Используем режим Запись и флаг Загрузка
    Объект.ОбменДанными.Загрузка = Истина;
    Попытка
        Объект.Записать(РежимЗаписиДокумента.Запись);
    Исключение
        ЗаписьЖурналаРегистрации("ОшибкаЗаполненияЦен", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
    КонецПопытки;
КонецЦикла;

Альтернативный вариант: Использование регистров сведений

Если база данных насчитывает миллионы записей, а изменение структуры документов (добавление колонок в ТЧ) нежелательно из-за раздувания объема базы, рассмотрим архитектурно более изящное решение.

Вместо добавления колонок в сам документ, можно создать Регистр сведений (например, "ДополнительныеДанныеДокументов").

Преимущества этого метода:

Риски и предостережения

Разберем опасности, которые подстерегают при использовании режима РежимЗаписиДокумента.Запись:

  1. Механизм очистки движений: В некоторых конфигурациях (особенно самописных) в процедуре ПередЗаписью или ПриЗаписи может стоять код Движения.Запасы.Очистить(). Если не использовать флаг Загрузка = Истина, то даже простая запись может стереть существующие движения документа.
  2. Подписки на события: На документ могут быть назначены подписки на событие "При записи". Убедитесь, что они не выполняют лишних действий, если документ записывается без проведения.

Таким образом, самым надежным способом программного изменения данных в проведенном документе является сочетание РежимЗаписиДокумента.Запись и ОбменДанными.Загрузка = Истина, выполненное в рамках внешней обработки, а не в модуле формы.

← На главную