Почему новый документ 1С становится проведенным при записи в режиме "Запись" и как это исправить

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

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

Анализ ситуации: документ проведен, но движений нет

Рассмотрим сценарий, с которым столкнулся автор темы. Из формы документа ПриобретениеТоваровУслуг программно создается новый документ ПередачаТоваровМеждуОрганизациями. Разработчик использует стандартный подход: создает новый объект, заполняет его данными из текущего документа и записывает. Однако после выполнения кода в списке документов новый объект помечается как проведенный.

Важный технический нюанс: статус "Проведен" в 1С — это не просто признак наличия записей в регистрах. Это значение системного реквизита Проведен, который хранится в таблице документа в базе данных. Когда платформа отрисовывает список документов, она ориентируется именно на это булево значение. Если оно равно Истина, пользователь видит иконку проведения, даже если процедура ОбработкаПроведения никогда не запускалась.

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

Выясняем причину: коварство функции ЗаполнитьЗначенияСвойств

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


// Допустим, ОбъектОснование — это уже проведенный документ
НовыйДокумент = Документы.ПередачаТоваровМеждуОрганизациями.СоздатьДокумент();
ЗаполнитьЗначенияСвойств(НовыйДокумент, ОбъектОснование);
НовыйДокумент.Записать(РежимЗаписиДокумента.Запись);

Проанализируем работу функции ЗаполнитьЗначенияСвойств. Этот метод работает по принципу прямого сопоставления имен свойств источника и приемника. Он не обладает "интеллектом" и не понимает, что Дата — это реквизит, который нужно копировать, а Проведен — это статус, который у нового документа должен быть Ложь. Поскольку в исходном документе Проведен = Истина, это значение успешно копируется в новый объект.

Многие разработчики пытаются решить проблему использованием флага ОбменДанными.Загрузка = Истина. Рассмотрим подробнее: этот флаг отключает проверки в модулях (ПередЗаписью, ПриЗаписи), но он **не меняет** значения реквизитов. Если вы явно или косвенно установили Проведен = Истина, платформа запишет это в базу именно в таком виде, считая, что разработчик знает, что делает.

Решение №1: Использование списка исключений

Самый простой и правильный способ при использовании ЗаполнитьЗначенияСвойств — это задействовать третий параметр функции, который позволяет указать список исключаемых свойств. Мы рекомендуем всегда исключать системные поля при программном создании документов на базе существующих.

Рассмотрим пример кода с исправлением:


НовыйДокумент = Документы.ПередачаТоваровМеждуОрганизациями.СоздатьДокумент();
// Указываем через запятую свойства, которые НЕ должны копироваться
СписокИсключений = "Проведен, ПометкаУдаления, Номер, Ссылка";
ЗаполнитьЗначенияСвойств(НовыйДокумент, ОбъектОснование, СписокИсключений);

НовыйДокумент.Дата = ТекущаяДата(); // Устанавливаем актуальную дату
НовыйДокумент.Записать(РежимЗаписиДокумента.Запись);

Этот метод позволяет сохранить контроль над процессом и гарантирует, что статус нового документа будет соответствовать действительности.

Решение №2: Использование метода Скопировать()

Если ваша задача — создать идентичный документ того же типа, воспользуйтесь встроенным методом Скопировать(). Платформа 1С при выполнении этого метода автоматически очищает ключевые системные поля.

Разберем, как это работает:


// ИсходныйДокументСсылка — ссылка на документ-образец
НовыйОбъект = ИсходныйДокументСсылка.Скопировать();
// На выходе получаем объект, где Проведен = Ложь, ПометкаУдаления = Ложь, а Номер пустой
НовыйОбъект.Дата = ТекущаяДата();
НовыйОбъект.Записать(РежимЗаписиДокумента.Запись);

Важно: этот метод подходит только в том случае, если документ-приемник имеет тот же тип, что и документ-источник.

Решение №3: Метод Заполнить() и обработка заполнения

В типовых конфигурациях (УТ 11, ERP 2.5, КА) наиболее правильным архитектурным решением является использование механизма заполнения по основанию. Вместо ручного копирования свойств мы вызываем метод Заполнить(), который инициирует событие ОбработкаЗаполнения в модуле объекта создаваемого документа.

Посмотрим на реализацию:


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

В этом случае за перенос данных отвечает специально написанный код в модуле документа. Статус проведения там никогда не копируется, а заполняются только бизнес-значимые реквизиты (Контрагент, Организация, Товары и т.д.).

Резюме для разработчика

Подведем итоги нашего анализа. Чтобы не допускать появления документов-"призраков", которые значатся проведенными, но не имеют движений, придерживайтесь следующих правил:

  1. При использовании ЗаполнитьЗначенияСвойств всегда проверяйте, не попадает ли в целевой объект реквизит Проведен.
  2. Если документ создается программно и вы видите его проведенным в списке — проверьте, не копируете ли вы данные из уже проведенного объекта.
  3. В качестве "быстрой заплатки" можно явно сбрасывать флаг: ДокументОбъект.Проведен = Ложь; перед вызовом метода Записать().
  4. Статус Проведен должен управляться исключительно платформой через РежимЗаписиДокумента.Проведение, ручная манипуляция этим свойством — плохая практика, ведущая к нарушению целостности данных.

Использование правильных методов копирования и заполнения данных избавит вас от ошибок в учете и недоумения пользователей, видящих пустые отчеты по "проведенным" документам.

← На главную