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

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

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

В данной статье мы подробно разберем, почему вызов метода Прочитать() может «сломать» копирование, как правильно использовать проверку ЭтоНовый() и каким образом оптимизировать процедуры расчета весогабаритных характеристик, чтобы не нарушать целостность данных.

Разбор проблемы: почему данные исчезают при копировании

Рассмотрим стандартную ситуацию: в справочнике «Номенклатура» в процедуру ПередОткрытием добавляется код для автоматического расчета объемов и веса, после чего вызывается метод ЭтаФорма.Прочитать(). Сразу после этого пользователи замечают, что при нажатии кнопки «Скопировать» новая карточка открывается абсолютно пустой, хотя должна быть заполнена данными из оригинала.

Выясним причину этого поведения:

  1. Когда пользователь нажимает «Скопировать», система создает в оперативной памяти новый объект и копирует в него значения реквизитов из образца.
  2. В этот момент объект считается «новым», он еще не записан в базу данных и не имеет уникальной ссылки (точнее, ссылка пустая).
  3. Метод ЭтаФорма.Прочитать() дает платформе команду: «Возьми ссылку текущего объекта, найди его в базе данных и перезаполни форму данными оттуда».
  4. Поскольку нового (копируемого) объекта в базе еще нет, поиск по пустой ссылке возвращает пустоту, и метод Прочитать() добросовестно очищает все поля формы.

Решение 1: Использование проверки на новый объект

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

В обработчике ПередОткрытием (для обычных форм) или ПриСозданииНаСервере (для управляемых) необходимо добавить условие:


Процедура ПередОткрытием(Отказ, СтандартнаяОбработка)
    // Стандартные проверки конфигурации
    Если НЕ глСправочники_ПередОткрытием(ЭтаФорма, Отказ, СтандартнаяОбработка) Тогда 
        Возврат; 
    КонецЕсли;

    // Выполняем расчет и чтение только если объект уже записан в базу
    Если Не ЭтоНовый() Тогда
        ПосчитатьОбъемы(Ссылка);
        ЭтаФорма.Прочитать();
    КонецЕсли;
КонецПроцедуры

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

Решение 2: Правильная обработка реквизитов при копировании

Часто возникает дополнительная задача: при копировании номенклатуры нужно оставить заполненными основные поля (наименование, группа), но обнулить специфические данные, такие как вес или объем. Рассмотрим, как это сделать правильно на уровне модуля объекта.

Для этого лучше всего использовать предопределенную процедуру ПриКопировании в модуле объекта. Проанализируем пример кода:


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

Использование этого метода гораздо профессиональнее, чем попытки «обнуления» в коде формы, так как логика сработает при любом способе копирования (программном или интерактивном).

Критический анализ процедуры расчета (ПосчитатьОбъемы)

Проанализируем процедуру расчета, которая часто становится причиной проблем. В исходном коде часто встречается ошибка — выполнение Записать() внутри цикла при открытии формы. Это крайне плохая практика.

Рассмотрим причины, почему нельзя записывать объект в обработчиках открытия:

Разберем по шагам, как переписать процедуру правильно:


Процедура ПосчитатьОбъемы(ТекущаяСсылка)
    // Выполняем запрос один раз для получения агрегированных данных
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   СУММА(ТЧ.ШаблонУпаковки.Вес) КАК ИтогоВес,
        |   СУММА(ТЧ.ШаблонУпаковки.Объем) КАК ИтогоОбъем
        |ИЗ
        |   Справочник.ШаблоныСхемПакования.ТЧСостав КАК ТЧ
        |ГДЕ
        |   ТЧ.Ссылка.Владелец = &Ссылка";
    
    Запрос.УстановитьПараметр("Ссылка", ТекущаяСсылка);
    Выборка = Запрос.Выполнить().Выбрать();
    
    Если Выборка.Следующий() Тогда
        // Вместо записи в базу, мы просто обновляем реквизиты объекта в памяти формы
        Вес = Выборка.ИтогоВес;
        Объем = Выборка.ИтогоОбъем;
        // Записывать объект НЕ НУЖНО. Пользователь сам нажмет "ОК", если захочет.
    КонецЕсли;
КонецПроцедуры

Методические рекомендации

Подведем итог и сформулируем правила работы с данными формы в 1С:

  1. Никогда не используйте ЭтаФорма.Прочитать() без проверки ЭтоНовый(), если не хотите потерять данные при копировании или вводе новых элементов.
  2. Избегайте записи объекта (Записать()) в процедурах ПередОткрытием или ПриОткрытии. Эти события предназначены для визуальной настройки интерфейса и подготовки данных для отображения, а не для модификации базы.
  3. Для управляемых форм (v8.3): вместо ПередОткрытием используйте ПриСозданииНаСервере. Там работа идет с данными через Объект, и потребность в Прочитать() возникает крайне редко.
  4. Используйте запросы грамотно. Не делайте запрос в цикле. Если нужно получить итоги по подчиненному справочнику, используйте агрегатные функции СУММА и группировки.
  5. ОбработкаЗаполнения: Если ваша конфигурация современная, рассмотрите использование процедуры ОбработкаЗаполнения в модуле объекта. Она вызывается и при копировании, и при создании на основании, что позволяет централизованно управлять заполнением реквизитов.

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

← На главную