Как правильно программно записывать значения дополнительных реквизитов в 1С:ERP, чтобы данные не пропадали?

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

При работе с конфигурациями на базе БСП (Библиотека стандартных подсистем), такими как ERP 2.4, Комплексная автоматизация или Управление торговлей 11, разработчики часто сталкиваются с проблемой: программно добавленное значение в табличную часть ДополнительныеРеквизиты исчезает после повторного нажатия кнопки "Записать" или при определенных действиях на форме. Разберем, почему это происходит и как реализовать задачу правильно.

Почему данные пропадают при повторной записи?

Проанализируем ситуацию: когда вы открываете форму объекта, подсистема "Свойства" считывает данные из базы и кэширует их в памяти формы (в специальных реквизитах формы или коллекциях). Если вы используете процедуру ПередЗаписьюНаСервере в расширении формы и напрямую модифицируете ТекущийОбъект.ДополнительныеРеквизиты, данные попадают в объект и записываются в базу. Однако внутреннее состояние подсистемы свойств в памяти формы не обновляется.

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

Решение 1: Перенос логики в модуль объекта (Рекомендуемый способ)

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

Рассмотрим пример реализации в расширении модуля объекта ДоговорыКонтрагентов:


&После("ПередЗаписью")
Процедура Расш1_ПередЗаписью(Отказ, Замещение, ПараметрыЗаписи)
    
    // Проверяем, что это новый объект (еще не записан в базу)
    Если ЭтоНовый() Тогда
        
        // Поиск свойства по наименованию (лучше использовать предопределенный идентификатор, если возможно)
        СвойствоДатаСоздания = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("ДатаСоздания");
        
        Если Не СвойствоДатаСоздания.Пустая() Тогда
            // Ищем, нет ли уже такой строки (на случай повторного вызова)
            СтрокаРеквизита = ДополнительныеРеквизиты.Найти(СвойствоДатаСоздания, "Свойство");
            
            Если СтрокаРеквизита = Неопределено Тогда
                НовыйРеквизит = ДополнительныеРеквизиты.Добавить();
                НовыйРеквизит.Свойство = СвойствоДатаСоздания;
                НовыйРеквизит.Значение = ТекущаяДата();
            Иначе
                // Если строка уже есть, но значение пустое — заполняем
                Если Не ЗначениеЗаполнено(СтрокаРеквизита.Значение) Тогда
                    СтрокаРеквизита.Значение = ТекущаяДата();
                КонецЕсли;
            КонецЕсли;
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

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

Решение 2: Использование программного интерфейса БСП (УправлениеСвойствами)

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

Разберем использование метода УправлениеСвойствами.ЗаписатьСвойствоУОбъекта. Этот метод принудительно записывает значение в базу данных.

Пример кода:


// Определяем ссылку на свойство
СвойствоОбъекта = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("ДатаСоздания");

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

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

Решение 3: Правильная работа в форме объекта

Если логику необходимо оставить в ПередЗаписьюНаСервере на форме, нужно учитывать, что форма управляет отображением доп. реквизитов через специальные динамические реквизиты. Чтобы данные не затирались, после программного изменения ТекущийОбъект.ДополнительныеРеквизиты, необходимо обновить коллекцию свойств в параметрах формы.

Проанализируем шаги, которые помогут сохранить стабильность:

  1. Используйте поиск свойства не по наименованию, а через владельца (Набор свойств), так как НайтиПоНаименованию может вернуть дубликат из другого справочника.
  2. Проверяйте наличие реквизита в коллекции ДополнительныеРеквизиты перед добавлением, чтобы не плодить одинаковые строки.
  3. Если вы скрываете реквизит на форме, убедитесь, что он вообще доступен для записи в данном контексте (проверка прав и состава набора свойств).

Рассмотрим правильный код для формы (с проверкой существующей записи):


&После("ПередЗаписьюНаСервере")
Процедура Расш1_ПередЗаписьюНаСервереПосле(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    
    // Проверка на новый объект в контексте формы
    Если ТекущийОбъект.Ссылка.Пустая() Тогда
        
        СвойствоСсылка = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("ДатаСоздания");
        
        Если ЗначениеЗаполнено(СвойствоСсылка) Тогда
            // Пытаемся найти существующую строку, чтобы не дублировать
            Отбор = Новый Структура("Свойство", СвойствоСсылка);
            НайденныеСтроки = ТекущийОбъект.ДополнительныеРеквизиты.НайтиСтроки(Отбор);
            
            Если НайденныеСтроки.Количество() = 0 Тогда
                НовыйРеквизит = ТекущийОбъект.ДополнительныеРеквизиты.Добавить();
                НовыйРеквизит.Свойство = СвойствоСсылка;
                НовыйРеквизит.Значение = ТекущаяДата();
            Иначе
                // Если строка уже создана в этом сеансе, просто обновляем значение
                НайденныеСтроки[0].Значение = ТекущаяДата();
            КонецЕсли;
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

Рекомендации по выбору инструмента

Выясним причину, почему один метод лучше другого. В 1С:ERP работа со свойствами сильно завязана на подсистему УправлениеСвойствами. Прямая правка табличной части — это крайняя мера.

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

Основные выводы:

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

← На главную