При работе с расширениями в 1С часто возникает ситуация, когда нам необходимо добавить новый функционал к типовым объектам конфигурации, не снимая при этом основную конфигурацию с поддержки. Одним из таких типовых сценариев является реализация механизма "Ввод на основании", когда один документ должен создаваться на базе другого. Однако при попытке добавить типовой документ в расширение и отредактировать его свойства, например, состав документов-оснований, мы сталкиваемся с тем, что привычный редактор объекта конфигурации просто не открывается. Давайте вместе разберемся, почему это происходит и как правильно решить данную задачу.
Прежде всего, давайте выясним причину, по которой мы не можем открыть полный редактор объекта конфигурации, такого как документ "ПриходныйОрдерНаТовары", после того как добавили его в расширение. Это ограничение является фундаментальной особенностью механизма расширений в 1С и продиктовано его основной целью – обеспечить доработку прикладных решений без изменения основной конфигурации и сохранением ее на поддержке.
Когда мы заимствуем объект конфигурации из основной конфигурации в расширение, мы не создаем его копию, которую можно было бы полностью модифицировать. Вместо этого, расширение получает своего рода "ссылку" или "представление" этого объекта. Это позволяет нам:
&Перед, &После, &Вместо), мы можем перехватывать выполнение стандартных процедур и функций, добавляя свою логику до, после или вместо типовой.Однако, расширение не позволяет нам напрямую изменять структуру самого объекта конфигурации. Это означает, что мы не можем:
Причина проста: если бы мы могли изменять метаданные заимствованного объекта напрямую, это привело бы к изменению структуры таблиц базы данных, относящихся к основной конфигурации. Такое изменение сломало бы механизм обновления типовой конфигурации, поскольку ее поставщик ожидает определенную структуру данных. Расширения созданы для того, чтобы быть "накладками", которые дополняют, но не изменяют основную структуру.
Поэтому, когда мы пытаемся открыть редактор для заимствованного документа, система не предоставляет нам полного доступа к его метаданным, что проявляется в невозможности открыть привычное окно редактирования со вкладками "Основные", "Подсистемы" и т.д. Вместо этого, мы должны работать с заимствованными объектами через их формы и модули, используя механизмы, специально разработанные для расширений.
Итак, мы столкнулись с проблемой: нам нужно, чтобы документ "ПриходныйОрдерНаТовары" (типовой, заимствованный) мог быть создан на основании нашего нового документа "ПринятьТоварПоФакту" (созданного в расширении). При этом прямой доступ к редактированию свойств "ПриходныйОрдерНаТовары" ограничен. Решим эту задачу, используя рекомендуемый механизм расширений – общие команды и перехватчики событий.
Механизм "Ввод на основании" в 1С фактически представляет собой набор команд, которые появляются в контекстном меню документа или его формы списка. Для того чтобы наш новый документ мог служить основанием для типового, нам необходимо создать такую команду в нашем расширении и связать ее с типовым документом. Разберем по шагам, как это сделать. При необходимости можно использовать расширение для создания объектов на основании других объектов.
Если у нас еще нет документа, который будет являться основанием для создания другого документа, мы его создаем непосредственно в расширении. В нашем случае это будет документ "ПринятьТоварПоФакту".
ПринятьТоварПоФакту. Мы можем добавить к нему необходимые реквизиты и табличные части, которые будут содержать данные для заполнения Приходного ордера. Например, реквизиты для склада, контрагента и табличную часть со списком товаров и их фактическим количеством.Этот документ будет источником данных для Приходного ордера.
В нашем случае это документ "ПриходныйОрдерНаТовары" из конфигурации УТ 11. Мы его заимствуем, чтобы иметь возможность работать с его формами и модулями.
ПриходныйОрдерНаТовары.ПриходныйОрдерНаТовары появится в дереве объектов нашего расширения. Обратите внимание, что его пиктограмма будет отличаться, указывая на то, что это заимствованный объект.Несмотря на то, что мы не можем изменить его основные свойства, мы теперь можем перехватывать его методы и работать с его формами.
Это ключевой шаг для реализации нужного функционала. Общая команда будет отвечать за то, чтобы в контекстном меню нашего документа "ПринятьТоварПоФакту" появилась опция "Создать Приходный ордер", а также за инициализацию процесса создания и заполнения нового документа.
СоздатьПриходныйОрдерНаОсновании.Командная панель формы. Создать на основании. Именно это позволит команде появиться в нужном подменю документа-основания.ДокументСсылка.ПринятьТоварПоФакту. Это свойство очень важно, так как оно указывает системе, для каких документов будет активна эта команда.Видимость и Доступность.Теперь, когда команда создана и настроена, нам нужно написать код, который будет создавать "ПриходныйОрдерНаТовары" и заполнять его данными из "ПринятьТоварПоФакту".
4.1. Код в модуле Общей команды:
В модуле общей команды СоздатьПриходныйОрдерНаОсновании (на стороне клиента) нам нужно получить документ-основание, создать новый "ПриходныйОрдерНаТовары" и открыть его форму.
// В модуле общей команды СоздатьПриходныйОрдерНаОсновании
&НаКлиенте
Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)
// ПараметрКоманды содержит ссылку на документ-основание
// (например, ДокументСсылка.ПринятьТоварПоФакту),
// для которого была вызвана команда "Создать на основании".
Если ТипЗнч(ПараметрКоманды) = Тип("ДокументСсылка.ПринятьТоварПоФакту") Тогда
// Создаем новый документ ПриходныйОрдерНаТовары
// Используем менеджер документа для создания объекта
НовыйДокументОбъект = Документы.ПриходныйОрдерНаТовары.СоздатьДокумент();
// Вызываем стандартный метод Заполнить, передавая документ-основание.
// Этот метод запустит обработчики события ОбработкаЗаполнения
// как типовые, так и наши в расширении.
НовыйДокументОбъект.Заполнить(ПараметрКоманды);
// Открываем форму нового документа для дальнейшего редактирования
// или сохранения пользователем
Форма = НовыйДокументОбъект.ПолучитьФорму();
Форма.Открыть();
КонецЕсли;
КонецПроцедуры
Этот код выполняет основную работу: создает новый экземпляр "Приходного ордера" и вызывает его метод Заполнить(), передавая ему наш документ "ПринятьТоварПоФакту" в качестве основания. Именно метод Заполнить() отвечает за то, чтобы данные из документа-основания перенеслись в новый документ. По умолчанию типовой "ПриходныйОрдерНаТовары" скорее всего не знает о нашем новом документе "ПринятьТоварПоФакту" и не сможет автоматически перенести специфичные для него данные.
4.2. Перехват обработчика ОбработкаЗаполнения в модуле объекта "ПриходныйОрдерНаТовары":
Чтобы типовой "ПриходныйОрдерНаТовары" мог корректно заполняться данными из "ПринятьТоварПоФакту", нам нужно добавить свою логику заполнения. Мы не можем напрямую модифицировать модуль объекта типового документа, но мы можем использовать механизм перехватчиков расширения.
ПриходныйОрдерНаТовары.&После для перехвата стандартного обработчика ОбработкаЗаполнения.
// В модуле объекта заимствованного документа ПриходныйОрдерНаТовары (в расширении)
&После("ОбработкаЗаполнения")
Процедура ПриходныйОрдерНаТовары_ОбработкаЗаполненияПосле(Основание)
// Основание - это тот документ, который был передан в метод Заполнить()
// В нашем случае, это ДокументСсылка.ПринятьТоварПоФакту.
Если ТипЗнч(Основание) = Тип("ДокументСсылка.ПринятьТоварПоФакту") Тогда
// Здесь мы описываем логику переноса данных из документа
// "ПринятьТоварПоФакту" в "ПриходныйОрдерНаТовары".
// "ЭтотОбъект" в данном контексте - это создаваемый ПриходныйОрдерНаТовары.
// Пример заполнения реквизитов:
// Предположим, у ПринятьТоварПоФакту есть реквизиты СкладПриемки, КонтрагентПоставщик.
// А у ПриходныйОрдерНаТовары есть реквизиты Склад, Контрагент.
Если Основание.Свойство("СкладПриемки") Тогда // Проверяем наличие свойства, если оно добавлено в расширение
ЭтотОбъект.Склад = Основание.СкладПриемки;
КонецЕсли;
Если Основание.Свойство("КонтрагентПоставщик") Тогда
ЭтотОбъект.Контрагент = Основание.КонтрагентПоставщик;
КонецЕсли;
// Пример заполнения табличной части:
// Предположим, у ПринятьТоварПоФакту есть табличная часть "Товары" с колонками "Номенклатура", "КоличествоПоФакту".
// А у ПриходныйОрдерНаТовары есть табличная часть "Товары" с колонками "Номенклатура", "Количество".
Если Основание.Свойство("Товары") Тогда
Для Каждого СтрокаОснования Из Основание.Товары Цикл
СтрокаНовогоДокумента = ЭтотОбъект.Товары.Добавить();
СтрокаНовогоДокумента.Номенклатура = СтрокаОснования.Номенклатура;
СтрокаНовогоДокумента.Количество = СтрокаОснования.КоличествоПоФакту; // Переносим фактическое количество
// Добавляем заполнение других колонок табличной части, если необходимо
// Например, Цена, Сумма, СтавкаНДС и т.д.
// СтрокаНовогоДокумента.Цена = ...
КонецЦикла;
КонецЕсли;
// Если есть другие специфичные для вашего документа реквизиты,
// добавленные в расширение, их тоже можно заполнить здесь.
// Например, если в ПриходныйОрдерНаТовары мы добавили реквизит
// "ДокументОснованиеФактический" через расширение:
Если ЭтотОбъект.Свойство("ДокументОснованиеФактический") Тогда
ЭтотОбъект.ДокументОснованиеФактический = Основание;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Важно понимать, что типовой метод ОбработкаЗаполнения "ПриходногоОрдераНаТовары" может быть вызван с разными типами оснований. Наша процедура ПриходныйОрдерНаТовары_ОбработкаЗаполненияПосле будет выполняться после типового кода, если такое основание обработано. Если типовая конфигурация не знает про наш документ "ПринятьТоварПоФакту", она просто проигнорирует его, и вся логика заполнения ляжет на нашу процедуру.
Использование аннотации &После позволяет нам дополнить стандартную логику, не затрагивая ее. Если бы нам нужно было полностью заменить типовое поведение, мы использовали бы &Вместо. Для добавления логики до типовой – &Перед.
Последний, но не менее важный шаг – убедиться, что у пользователей, которые должны использовать этот функционал, есть необходимые права.
СоздатьПриходныйОрдерНаОсновании) и на наш новый документ (ПринятьТоварПоФакту). Убедимся, что есть права на "Просмотр" и "Использование".Без корректно настроенных прав, даже если вся логика написана верно, пользователи не увидят команду или не смогут создать документ.
Таким образом, мы видим, что, несмотря на невозможность прямого редактирования заимствованных объектов конфигурации, механизм расширений предоставляет нам мощные инструменты для добавления и изменения функционала. Используя общие команды, которые служат точками входа для реализации "Ввода на основании", и перехватчики событий (например, &После("ОбработкаЗаполнения")) в модулях заимствованных объектов, мы можем реализовать сложную логику взаимодействия между нашими новыми документами и типовыми объектами, полностью сохраняя возможность обновления основной конфигурации.
Это требует более глубокого понимания архитектуры расширений и умения работать с модулями, но дает нам гибкость и безопасность, необходимые для профессиональной разработки на платформе 1С:Предприятие. Для автоматического переноса реквизитов и табличных частей без программирования можно использовать обработку для создания документов на основании.