Почему после записи документа в 1С очищаются реквизиты формы, не связанные с данными?

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

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

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

Решение 1: Пересчет данных при каждом открытии и после записи

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

Разберем по шагам, как это реализовать:

  1. Создадим на сервере специальную процедуру, которая будет выполнять все необходимые вычисления и заполнять наши реквизиты формы. Это помогает избежать дублирования кода.
  2. Будем вызывать эту процедуру из двух ключевых серверных обработчиков событий формы:
    • ПриСозданииНаСервере — сработает один раз, когда форма только открывается.
    • ПослеЗаписиНаСервере — сработает каждый раз после успешной записи объекта.

Посмотрим на пример: допустим, у нас есть документ "Заказ", а на форме мы хотим видеть расчетное поле ПроцентВыполненияЗаказа, которое не хранится в документе.


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

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    РассчитатьДополнительныеРеквизиты();
КонецПроцедуры

&НаСервере
Процедура ПослеЗаписиНаСервере(ТекущийОбъект, ПараметрыЗаписи)
    РассчитатьДополнительныеРеквизиты();
КонецПроцедуры

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

Решение 2: Хранение данных в базе данных

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

1. Добавление реквизитов в сам объект.

Это самый надежный способ. Мы просто добавляем новый реквизит (например, ПроцентВыполненияЗаказа) в сам объект конфигурации (документ "Заказ"). Расчет этого реквизита можно производить в серверном обработчике ПередЗаписьюНаСервере. Таким образом, данные будут записаны вместе с документом и всегда будут доступны.


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

2. Использование отдельного регистра сведений.

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

Решение 3: Использование временного хранилища

Этот способ позволяет "перенести" наши расчетные данные через процедуру записи. Механизм работает так: перед записью мы сохраняем данные в специальное временное хранилище на сервере, а после записи — забираем их оттуда и снова помещаем на форму.

Разберем по шагам:

  1. В обработчике ПередЗаписьюНаСервере мы помещаем значение нашего реквизита во временное хранилище с помощью функции ПоместитьВоВременноеХранилище(). Эта функция возвращает уникальный адрес, который мы сохраняем в переменную.
  2. В обработчике ПослеЗаписиНаСервере мы используем этот адрес и функцию ПолучитьИзВременногоХранилища(), чтобы получить наши данные обратно и присвоить их реквизиту формы.

Посмотрим на пример кода:


&НаСервере
Перем АдресВременногоХранилища;

&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    // Помещаем значение нашего реквизита формы во временное хранилище
    АдресВременногоХранилища = ПоместитьВоВременноеХранилище(Объект.ПроцентВыполненияЗаказа, УникальныйИдентификатор);
КонецПроцедуры

&НаСервере
Процедура ПослеЗаписиНаСервере(ТекущийОбъект, ПараметрыЗаписи)
    // Получаем данные из хранилища и снова устанавливаем в реквизит
    ДанныеИзХранилища = ПолучитьИзВременногоХранилища(АдресВременногоХранилища);
    Если ДанныеИзХранилища <> Неопределено Тогда
        Объект.ПроцентВыполненияЗаказа = ДанныеИзХранилища;
    КонецЕсли;
КонецПроцедуры

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

Решение 4: Кэширование данных на время сеанса

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

Платформа 1С предоставляет отличный механизм: общие модули с повторным использованием возвращаемых значений. Для этого нужно:

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

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

Пример функции в таком модуле:


// Общий модуль "РасчетныеФункцииСерверКэшируемый"
Функция РассчитатьСложныйПоказатель(Параметр1, Параметр2) Экспорт
    
    // ... здесь очень долгие и сложные вычисления ...
    Результат = ...; 
    Возврат Результат;

КонецФункции

Этот подход значительно ускоряет работу формы при многократных обращениях к одним и тем же расчетным данным.

← К списку