Как в общей форме «Цены и валюта» определить документ-владелец и ограничить доступность полей?

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

При разработке и кастомизации типовых конфигураций 1С (особенно таких как УПП 1.3, УТ 10.3, КА 1.1 или ERP) программисты часто сталкиваются с необходимостью изменить поведение общей формы ФормаЦеныИВалюта. Эта форма отвечает за выбор типа цен, валюты, налоговых режимов (НДС) и скидок для табличных частей различных документов. Основная сложность заключается в том, что форма универсальна, и если нам требуется заблокировать или скрыть определенные поля только для одного конкретного документа (например, для «Поступления товаров и услуг»), стандартные методы не всегда очевидны.

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

Метод 1. Определение документа-владельца через свойство «ВладелецФормы»

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

Рассмотрим два варианта реализации этого метода в зависимости от типа используемого приложения.

Вариант А: Для обычного приложения (УПП 1.3, УТ 10.3, КА 1.1)

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


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

Вариант Б: Для управляемого приложения (ERP, КА 2, УТ 11, БП 3.0)

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


Если ЭтаФорма.ВладелецФормы <> Неопределено Тогда
    ИмяФормыВладельца = ЭтаФорма.ВладелецФормы.ИмяФормы;
    // Значение будет иметь вид: "Документ.ПоступлениеТоваровУслуг.Форма.ФормаДокумента"
    
    Если СтрНайти(ИмяФормыВладельца, "Документ.ПоступлениеТоваровУслуг") > 0 Тогда
        // Отключаем доступность управляемых элементов на форме цен и валют
        Элементы.НДСВключенВСтоимость.Доступность = Ложь;
        Элементы.ПорядокРегистрацииЦен.Доступность = Ложь;
    КонецЕсли;
КонецЕсли;

Метод 2. Использование типового механизма «Структуры запрещенных реквизитов»

Почему ключи в структуре запрещенных реквизитов, передаваемые при открытии формы, часто не совпадают с именами элементов на самой форме ФормаЦеныИВалюта? С этим вопросом часто сталкиваются начинающие разработчики.

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

  1. При вызове формы из документа формируется СтруктураЗапрещенных (в некоторых конфигурациях — СтруктураНередактируемыхРеквизитов). В нее помещаются имена реквизитов самого документа-источника (например, УчитыватьНДС, СуммаВключаетНДС).
  2. В общем модуле (например, Ценообразование) или в модуле самой формы происходит сопоставление переданной структуры с элементами формы. На форме элементы часто имеют префиксы (например, флаг на форме называется НовыйУчитыватьНДС или НовыйТипЦен).
  3. Код сопоставления выглядит примерно так:
    
    ФормаЦеныВалюты.ЭлементыФормы.НовыйУчитыватьНДС.Доступность = 
        НЕ СтруктураНередактируемыхРеквизитов.Свойство("УчитыватьНДС");
    

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

Посмотрим на пример вызова из формы документа «Поступление товаров и услуг»:


// Определяем структуру запрещенных к изменению реквизитов документа
СтруктураЗапрещенных = Новый Структура;
СтруктураЗапрещенных.Вставить("УчитыватьНДС");             // Заблокирует флаг НДС на форме
СтруктураЗапрещенных.Вставить("СуммаВключаетНДС");        // Заблокирует флаг включения НДС в сумму
СтруктураЗапрещенных.Вставить("РегистрироватьЦеныПоставщика"); // Заблокирует флаг регистрации цен

// Вызываем типовой метод открытия формы цен и валют
Ценообразование.ОткрытьФормуЦеныИВалюта(
    ДокументОбъект, 
    СтруктураРеквизитовДокумента, 
    мВалютаРегламентированногоУчета, 
    СтруктураЗапрещенных, 
    "Товары"
);

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

Метод 3. Современное решение с использованием расширений конфигурации (для управляемых форм)

Если вы работаете в современной конфигурации на управляемом интерфейсе (например, 1С:ERP или Комплексная автоматизация) и вам необходимо внедрить логику блокировки элементов формы цен без изменения типовой конфигурации (чтобы сохранить ее на полной поддержке), наилучшим решением будет использование Расширений конфигурации.

Выполним задачу по шагам:

  1. Создадим новое расширение в конфигураторе или откроем существующее.
  2. Добавим в расширение общую форму ФормаЦеныИВалюта.
  3. В модуле этой формы в расширении создадим обработчик события ПриСозданииНаСервере с аннотацией &После.

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


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

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

← На главную