Как изменить представление документа "Заказ поставщику" в 1С:УНФ, если стандартные обработчики отсутствуют или переопределяются?

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

При работе с конфигурацией 1С:УНФ у нас часто возникает необходимость адаптировать стандартное поведение программы под специфические бизнес-процессы. Одним из таких кейсов является изменение представления документов, например, для более информативного отображения в списках или при выборе. Нам предстоит рассмотреть ситуацию, когда стандартный подход для изменения представления документа "Заказ покупателя" работает без проблем, а для "Заказа поставщику" аналогичный код не дает желаемого результата. Мы выясним, почему так происходит, и как правильно решить эту задачу.

Понимание механизма изменения представления документа

Платформа 1С:Предприятие предоставляет нам стандартные обработчики событий в модуле менеджера объектов, которые позволяют управлять формированием представления. Это процедуры ОбработкаПолученияПолейПредставления и ОбработкаПолученияПредставления.

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

  2. ОбработкаПолученияПредставления: Здесь мы непосредственно формируем текстовое представление объекта, используя данные, полученные из ОбработкаПолученияПолейПредставления.

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


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

&Вместо("ОбработкаПолученияПредставления")
Процедура ЭСК_1ОбработкаПолученияПредставления(Данные, Представление, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь;
    сКмнт = Данные.Комментарий;
    Представление = "Сделка " + Данные.Договор.Наименование + сКмнт;
    //ПродолжитьВызов(Данные, Представление, СтандартнаяОбработка);
КонецПроцедуры

В этом примере мы указываем, что нам нужны поля "Номер", "Код", "Договор" и "Комментарий", а затем формируем представление в виде строки, комбинируя наименование договора и комментарий. Важно отметить использование СтандартнаяОбработка = Ложь;, что означает, что мы полностью перехватываем процесс формирования представления и не даем системе выполнить свою стандартную логику.

Анализ проблемы с документом "Заказ поставщику"

Наш опыт показывает, что аналогичный подход для документа "Заказ поставщику" не приводит к желаемому результату. Мы можем написать точно такой же код в расширении, поместив его в модуль менеджера документа "Заказ поставщику" с аннотацией &Вместо, но представление документа не изменится, хотя в отладчике мы увидим, что наш код выполняется. Пример такого неработающего кода:


&Вместо("ОбработкаПолученияПредставления")
Процедура ЭСК_1ОбработкаПолученияПредставления(Данные, Представление, СтандартнаяОбработка)
    // Вставить содержимое обработчика.
    СтандартнаяОбработка = ЛОЖЬ;
    Представление = "йцу ";
    //ПродолжитьВызов(Данные, Представление, СтандартнаяОбработка); // тут меня туда-сюда, нет результата
КонецПроцедуры

&Вместо("ОбработкаПолученияПолейПредставления")
Процедура ЭСК_1ОбработкаПолученияПолейПредставления(Поля, СтандартнаяОбработка)
    // Вставить содержимое обработчика.
    СтандартнаяОбработка = Ложь;
    //ПродолжитьВызов(Поля, СтандартнаяОбработка);
КонецПроцедуры

Мы видим, что даже простое присвоение "йцу " переменной Представление не влияет на итоговое отображение. В чем же причина такого поведения?

Основная разница, на которую мы должны обратить внимание, заключается в том, что в типовой конфигурации 1С:УНФ, в модуле менеджера документа "Заказ покупателя", процедура ОбработкаПолученияПредставления присутствует. А вот в модуле менеджера документа "Заказ поставщику" подобной процедуры нет. Когда мы используем аннотацию &Вместо в расширении, мы фактически пытаемся заменить процедуру, которой не существует в базовом объекте. Хотя платформа может позволить такой вызов (и мы видим это в отладчике), он не будет иметь эффекта, потому что сам механизм вызова этих обработчиков не сработает для несуществующей процедуры.

Выявление корневой причины: переопределение представления общим модулем

Однако отсутствие процедуры в модуле менеджера — это только часть проблемы. Даже если бы мы нашли способ "вставить" наш обработчик, в 1С:УНФ существует более высокоуровневый механизм, который отвечает за формирование представления документов и может перекрывать наши изменения. Мы говорим о процедуре ПолучитьПредставлениеДокументаСВходящимНомером, расположенной в общем модуле ДокументыУНФКлиентСервер.

Давайте посмотрим на упрощенный фрагмент этой типовой процедуры:


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

Мы видим, что эта процедура всегда формирует стандартное представление документа и, что самое критичное, устанавливает СтандартнаяОбработка = Ложь;. Это означает, что если эта процедура будет вызвана после нашего кода в модуле менеджера документа (если бы он даже был), она перезапишет наше значение переменной Представление своим собственным, и наши изменения будут отменены. Наши попытки изменить представление в модуле менеджера документа, таким образом, теряют смысл, потому что финальное слово остается за этой общей процедурой.

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

Решение проблемы: переопределение общей процедуры в расширении

Для успешного изменения представления документа "Заказ поставщику" нам необходимо переопределить процедуру ПолучитьПредставлениеДокументаСВходящимНомером в общем модуле ДокументыУНФКлиентСервер вашего расширения.

Разберем по шагам, как это сделать:

  1. Создайте расширение: Если у вас еще нет расширения, создайте его. Убедитесь, что оно имеет достаточные права, чтобы изменять общие модули.

  2. Добавьте общий модуль в расширение: Откройте расширение в конфигураторе. Найдите в дереве метаданных общий модуль ДокументыУНФКлиентСервер и добавьте его в ваше расширение (щелчок правой кнопкой мыши -> "Добавить в расширение"). В расширении он отобразится с припиской "[Расширение]".

  3. Переопределите процедуру: В модуле ДокументыУНФКлиентСервер вашего расширения найдите процедуру ПолучитьПредставлениеДокументаСВходящимНомером. Вам нужно будет использовать аннотацию &Вместо для этой процедуры, чтобы полностью заменить ее стандартную реализацию.

Пример кода, который мы разместим в модуле ДокументыУНФКлиентСервер нашего расширения:


&Вместо("ПолучитьПредставлениеДокументаСВходящимНомером")
Процедура ЭСК_ПолучитьПредставлениеДокументаСВходящимНомером(Источник, Данные, Представление, СтандартнаяОбработка) Экспорт

    // Проверяем, относится ли текущий объект к документу "Заказ поставщику"
    Если ТипЗнч(Источник) = Тип("ДокументМенеджер.ЗаказПоставщику") Тогда
        // Здесь мы формируем наше кастомное представление для "Заказа поставщику"
        // Используем поля, которые нам нужны. Если они не загружены,
        // возможно, придется получать их дополнительно из Данные.Ссылка

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

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

        // Здесь можно было бы прочитать "Договор" или "Комментарий", если они нужны
        // Например:
        // ДоговорОбъект = ЗаказПоставщикуОбъект.Договор;
        // Комментарий = ЗаказПоставщикуОбъект.Комментарий;

        // Для простоты примера, установим фиксированное представление
        Представление = "Наш ЗаказПоставщику: " + Строка(ЗаказПоставщикуОбъект.Номер) + " от " + Формат(ЗаказПоставщикуОбъект.Дата, "ДФ=dd.MM.yyyy");

        // Если вы хотите добавить Комментарий или Договор, и они есть в ЗаказеПоставщику
        // Представление = "Наш ЗаказПоставщику " + ЗаказПоставщикуОбъект.Номер + " (" + ЗаказПоставщикуОбъект.Договор.Наименование + ")" + ЗаказПоставщикуОбъект.Комментарий;

        СтандартнаяОбработка = Ложь; // Важно, чтобы наши изменения не были перекрыты
        Возврат;
    КонецЕсли;

    // Для всех остальных документов или случаев, когда это не Заказ поставщику,
    // мы можем вызвать оригинальную процедуру, если хотим сохранить ее логику
    // или просто завершить выполнение, если в расширении не требуется
    // дальнейшая обработка для других типов документов.
    // Если нам нужно, чтобы для других документов использовалась стандартная логика УНФ
    // без наших изменений, мы должны вызвать ПродолжитьВызов или не устанавливать
    // СтандартнаяОбработка = Ложь в случае, если тип не ЗаказПоставщику.

    // Но так как &Вместо полностью заменяет процедуру, если мы хотим,
    // чтобы для других документов работала стандартная логика, нам придется
    // ее воспроизвести или вызвать другую вспомогательную функцию УНФ.
    // В простейшем случае, если наша задача только для ЗаказаПоставщику,
    // а для остальных оставить как есть, то здесь мы можем просто
    // воспользоваться стандартным формированием представления.
    // Если мы хотим избежать циклического вызова (себя же), то не вызываем ПродолжитьВызов.

    // Для других документов, которые не ЗаказПоставщику,
    // мы можем использовать стандартную функцию ПредставлениеДокумента,
    // которая обычно используется в типовых конфигурациях.
    Представление = ПредставлениеДокумента(Данные, Источник.ПустаяСсылка, Истина);
    СтандартнаяОбработка = Ложь;

КонецПроцедуры

Разберем ключевые моменты этого кода:

  1. Аннотация &Вместо: Мы полностью заменяем типовую процедуру своей реализацией.

  2. Проверка типа Источник: Внутри процедуры мы проверяем, относится ли обрабатываемый объект к типу ДокументМенеджер.ЗаказПоставщику. Это позволяет нам применять нашу логику только к нужному документу, оставляя стандартное поведение для остальных.

  3. Формирование представления: В блоке Если ТипЗнч(Источник) = Тип("ДокументМенеджер.ЗаказПоставщику") Тогда мы формируем наше желаемое представление. Мы можем напрямую обращаться к полям объекта по его ссылке (Данные.Ссылка), чтобы получить нужные данные, если они не были переданы в структуру Данные изначально.

  4. СтандартнаяОбработка = Ложь;: Крайне важно установить этот параметр, чтобы убедиться, что система не будет пытаться применить свою стандартную логику после выполнения нашего кода.

  5. Обработка других документов: Для документов, которые не являются "Заказом поставщику", мы можем просто вызвать стандартную функцию ПредставлениеДокумента, чтобы сохранить их типовое представление. Это позволяет нашему расширению влиять только на целевой документ, не нарушая работу других частей системы.

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

Дополнительные рекомендации и отладка

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

Также помните о:

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

  2. Аннотации &ИзменениеИКонтроль: В некоторых случаях, когда вы изменяете или заменяете типовые процедуры, полезно использовать аннотацию &ИзменениеИКонтроль. Она помогает системе отслеживать изменения в типовом коде при обновлении конфигурации и может подсказать, когда ваш код в расширении может стать неактуальным.

Таким образом, для успешного изменения представления документа "Заказ поставщику" в 1С:УНФ нам необходимо не просто попытаться переопределить несуществующий обработчик в модуле менеджера, но и перехватить более глобальный механизм формирования представления, который находится в общем модуле ДокументыУНФКлиентСервер. Это позволит нам полностью контролировать, как будет отображаться наш документ, и добиться желаемого результата.

← На главную