Как правильно заполнить реквизиты новой формы на основании другого объекта без предварительного сохранения

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

При разработке механизмов создания связанных объектов в 1С:Предприятие 8 программисты часто сталкиваются с ситуацией, когда программно назначенные значения реквизитов «исчезают» или заменяются значениями по умолчанию сразу после открытия формы. Особенно часто это проявляется в зарплатных конфигурациях (ЗУП, КА, ERP) с такими полями, как ПериодВзаиморасчетов или ПериодРегистрации. Разберем подробно, почему это происходит и как решить проблему правильно.

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

Рассмотрим ситуацию, описанную в теме: при выполнении команды создания документа на клиенте получается форма, заполняется её объект, а затем форма открывается. Однако поле ПериодВзаиморасчетов упорно ставит дату по умолчанию. Выясним причину этого поведения. Проблема кроется в жизненном цикле формы и встроенных механизмах инициализации типовых конфигураций.

Когда мы используем метод ОткрытьФорму(), платформа инициирует цепочку событий:

  1. ОбработкаЗаполнения (в модуле объекта).
  2. ПриСозданииНаСервере (в модуле формы).
  3. ПриОткрытии (на клиенте).

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

Решение №1: Использование структуры «ЗначенияЗаполнения» (Рекомендуемое)

Вместо того чтобы вручную манипулировать объектом формы через КопироватьДанныеФормы, наиболее профессиональным подходом является передача параметров заполнения. Это позволяет платформе корректно вызвать событие ОбработкаЗаполнения в модуле объекта.

Рассмотрим, как изменить клиентский код для передачи данных:


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

&НаСервере
Функция ПолучитьДанныеДляЗаполненияНаСервере(СсылкаНаИсточник)
    
    СтруктураДанных = Новый Структура;
    СтруктураДанных.Вставить("ПериодРегистрации", СсылкаНаИсточник.Дата);
    // Важно: приводим дату к началу месяца для зарплатных реквизитов
    СтруктураДанных.Вставить("ПериодВзаиморасчетов", НачалоМесяца(СсылкаНаИсточник.Дата));
    
    Возврат СтруктураДанных;
    
КонецФункции

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

Решение №2: Переопределение логики в «ПриСозданииНаСервере» через параметры

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

Шаг 1. Передача произвольного параметра из клиентского кода:


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

Шаг 2. Обработка в модуле формы документа:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Проверяем наличие нашего параметра
    Если Параметры.Свойство("МойПериодВзаиморасчетов") Тогда
        Объект.ПериодВзаиморасчетов = Параметры.МойПериодВзаиморасчетов;
    КонецЕсли;
    
КонецПроцедуры

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

Особенности реквизита «ПериодВзаиморасчетов»

Проанализируем ситуацию с конкретным полем ПериодВзаиморасчетов. В конфигурациях 1С этот реквизит почти всегда имеет специфические требования:

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

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


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

Важный нюанс: Хотя этот способ «работает», он имеет существенный минус — в базе данных появляются «мусорные» документы, которые пользователь мог и не захотеть сохранять. Если пользователь закроет форму без сохранения, пустой (или полузаполненный) документ уже останется в списке. Поэтому мы рекомендуем использовать Решение №1 через параметры формы.

Порядок действий для исправления ситуации:

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

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

← На главную