Почему при проведении документа из управляемой формы затираются движения по регистрам?

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

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

При этом, если мы проведем этот же документ из формы списка или программно, все движения сформируются абсолютно правильно. Даже полное удаление программного кода из модуля формы не решает проблему. Посмотрим подробнее, в чем кроется причина такого странного поведения платформы 1С и как мы можем исправить эту ошибку.

Проанализируем ситуацию через отладчик

Разберем по шагам, что происходит внутри системы при попытке проведения документа. Если мы поставим точку останова в процедуре ПриЗаписи модуля набора записей проблемного регистра (например, партий товаров), то увидим следующую картину:

При проведении из формы списка (или из "правильной" формы):
Система заходит в процедуру дважды. Первый раз — при очищении старых движений перед проведением. Второй раз — при записи новых, корректно сформированных движений.

При проведении из "неправильной" управляемой формы:
Система заходит в процедуру трижды! Сначала происходит очищение движений. Затем идет запись правильных движений, которые сформировал модуль объекта. А вот в третий раз происходит запись пустого набора. Причем стек вызовов в этот момент пуст, как будто перезапись произошла сама по себе на уровне платформы.

Выясним причину: механика управляемых форм

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

Когда этот признак установлен, платформа считает управляемую форму "владельцем" этих данных. При нажатии стандартной кнопки проведения на форме происходит следующее:

  1. Платформа передает данные формы (клиентский контекст) на сервер. В этот момент коллекция движений на клиенте пуста, так как форма их не считывала при открытии.
  2. На сервере выполняется модуль объекта документа, включая процедуру ОбработкаПроведения. Формируются правильные движения, и они успешно записываются в базу данных.
  3. После завершения проведения платформа начинает синхронизировать состояние серверного объекта обратно с контекстом управляемой формы. Так как на клиенте набор записей числился как пустой, платформа возвращает эту "пустоту" обратно в объект, тем самым затирая только что созданные проводки пустыми наборами.

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

Способы решения проблемы

Устранить эту проблему можно несколькими путями. Рассмотрим каждый из них.

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

Альтернативные варианты: если движения нужны на форме

Иногда бизнес-логика все же требует, чтобы пользователь видел движения прямо в форме документа при ее открытии (например, в документах типа "Операция" или "Ручная корректировка"). Разберем, как поступить в этом случае, чтобы не сломать проведение.

Если вам нужно оставить движения в реквизитах формы, необходимо принудительно считывать их из базы данных. Например, в обработчике ПриСозданииНаСервере следует вызвать метод Движения.Прочитать() для нужных регистров. В таком случае в клиентском контексте будет находиться не пустой набор, а реальные данные, и при записи они не будут затирать сами себя пустотой.

Однако более правильным и оптимизированным подходом с точки зрения производительности управляемых форм является использование динамических списков. Не привязывайте элементы формы напрямую к коллекции Объект.Движения. Создайте отдельные динамические списки с основной таблицей нужного регистра и настройте отбор по регистратору (ссылке текущего документа). Это позволит выводить данные регистра пользователю без необходимости загружать весь набор записей в контекст формы документа и гонять его между клиентом и сервером.

← На главную