Почему очищается поле «Счет-основание» при изменении договора в новом документе на управляемых формах 1С?

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

Разработка интерфейсов на управляемых формах в платформе «1С:Предприятие 8.3» требует от программиста глубокого понимания механизмов взаимодействия клиента и сервера. Очень часто разработчики сталкиваются с весьма загадочным на первый взгляд поведением: в новом, еще не записанном документе при изменении одного реквизита (например, Договор) внезапно очищается другое, уже заполненное поле (например, СчетОснование).

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

1. Механизм «Связи параметров выбора» и его влияние на новые объекты

В абсолютном большинстве случаев виновником подобного поведения является стандартный платформенный механизм «Связи параметров выбора». Рассмотрим подробнее, как он устроен и почему он «не любит» новые, незаписанные объекты.

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

У этой связи есть критически важное свойство — «Режим изменения связанного значения». Данное свойство может принимать два значения:

Почему же эта очистка срабатывает исключительно для новых, незаписанных объектов? Дело в том, что в сложных типовых конфигурациях (таких как «Управление торговлей 11») связи параметров выбора могут быть завязаны не только на договор или контрагента напрямую, но и на саму ссылку текущего документа (например, для проверки истории взаиморасчетов или остатков по документу). Когда документ новый, его ссылка в базе данных еще не существует, то есть метод Объект.Ссылка.Пустая() возвращает значение Истина.

При обновлении данных формы после серверного вызова платформа 1С производит валидацию всех связей параметров выбора на клиенте. Так как объект еще не записан, вычисление параметров отбора по пустой ссылке отрабатывает некорректно или возвращает пустой результат. Платформа считает, что текущее значение поля СчетОснование больше не соответствует установленным связям параметров выбора, и, руководствуясь режимом «Очищать», принудительно обнуляет значение реквизита в момент отрисовки формы на клиенте.

Как решить эту проблему:

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

2. Некорректное использование преобразований данных формы на сервере

Вторая распространенная причина потери данных в незаписанных объектах — это использование в серверном коде разработчика методов ДанныеФормыВЗначение и ЗначениеВДанныеФормы. Проанализируем типичную ошибку в серверном обработчике события:


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

Давайте разберем по шагам, что происходит в этот момент на сервере для нового документа:

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

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

3. Скрытые алгоритмы и проверки Библиотеки стандартных подсистем (БСП)

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

Когда вы меняете договор, на сервере срабатывает подписка на события или общий модуль БСП, который проверяет совместимость. Примерный алгоритм проверки выглядит следующим образом:


// Пример логики проверки совместимости в типовом решении
Функция СчетСовместимСДоговором(СчетОснование, НовыйДоговор) Экспорт
    
    Если Не ЗначениеЗаполнено(НовыйДоговор) Тогда
        Возврат Ложь;
    КонецЕсли;
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	1
        |ИЗ
        |	Документ.СчетНаОплату КАК Счет
        |ГДЕ
        |	Счет.Ссылка = &СчетОснование
        |	И Счет.Договор = &Договор";
        
    Запрос.УстановитьПараметр("СчетОснование", СчетОснование);
    Запрос.УстановитьПараметр("Договор", НовыйДоговор);
    
    Возврат НЕ Запрос.Выполнить().Пустой();
    
КонецФункции

Если проверка возвращает Ложь (например, из-за того, что в новом договоре указана другая валюта или другая организация, либо из-за того, что документ еще не проведен и не зафиксирован в регистре сведений «Совместимость договоров»), типовой код программно сбрасывает значение счета-основания:


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

Чтобы точно определить, в какой именно строчке кода происходит сброс значения, воспользуемся мощным встроенным инструментом отладки — замером производительности:

  1. Откроем сеанс «1С:Предприятие» в режиме отладки и подготовим наш новый документ (заполним договор и счет).
  2. В конфигураторе перейдем в меню Отладка -> Замер производительности и активируем его (начнется запись выполняемых строк кода).
  3. В режиме предприятия изменим договор, дождемся окончания серверного вызова и очистки поля.
  4. В конфигураторе снова нажмем Замер производительности для его остановки.
  5. В открывшемся окне замера нажмем кнопку поиска (сочетание клавиш Ctrl + F) и введем имя нашего реквизита: СчетОснование (или имя очищающегося поля формы).
  6. Проанализируем все строки, где происходит присвоение значения этому реквизиту. Вы гарантированно обнаружите процедуру пересчета БСП, которая затирает ваши данные.

4. Неявное выполнение клиентского кода после вызова сервера

Обратим внимание на структуру клиентского обработчика события, представленного автором темы на форуме:


&НаКлиенте
Процедура ДоговорПриИзменении(Элемент)
    
    ЭтоДокументКорректировка = Ложь;
    ДоговорПриИзмененииСервер();
    
    ПересчетСумм(); // <--- Обратите внимание на этот вызов!
    
КонецПроцедуры

Автор утверждает, что данные пропадают именно в момент выхода из процедуры ДоговорПриИзмененииСервер(). Однако на клиенте шаг «выход из серверной процедуры» визуально и по логике выполнения отладчика сливается со следующей строкой кода — вызовом процедуры ПересчетСумм().

Очень часто разработчики забывают, что внутри клиентских процедур пересчета сумм, скидок, налогов или спецификаций может происходить неявное обращение к серверным данным «через точку». Например:


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

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

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

5. Кэширование представлений ссылок платформой на клиенте

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

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

Пошаговое руководство по исправлению проблемы

Резюмируя все вышесказанное, составим подробную инструкцию по локализации и исправлению этой неприятной ошибки:

  1. Шаг 1. Отключение связей параметров выбора.

    В конфигураторе временно очистите свойство «Связи параметров выбора» у элемента формы СчетОснование. Запустите сеанс «1С:Предприятие» и проверьте поведение формы нового документа при изменении договора. Если очистка прекратилась — причина найдена. Верните связи на место, но измените режим изменения связанного значения на «Не изменять».

  2. Шаг 2. Исключение влияния клиентских пересчетов.

    Закомментируйте вызовы всех процедур, которые выполняются в обработчике события после вызова сервера (в нашем случае — закомментируйте строку ПересчетСумм();). Проверьте работу формы. Если поле перестало очищаться — детально исследуйте закомментированную процедуру на наличие обращений «через точку» на клиенте.

  3. Шаг 3. Локализация сброса значения через табло отладчика.

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

  4. Шаг 4. Проверка использования «ДанныеФормыВЗначение».

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

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

← На главную