Работа с расширениями конфигурации в платформе «1С:Предприятие 8.3» — один из наиболее удобных способов кастомизации типовых решений без снятия их с поддержки. Однако при создании собственных объектов метаданных (справочников, документов, регистров) или добавлении реквизитов к существующим объектам разработчики часто сталкиваются с неочевидным поведением платформы. Наиболее распространенные проблемы связаны со "слепотой" Конструктора запросов во внешних обработках и невозможностью выбрать новые типы данных в параметрах запроса.
В этой статье мы подробно проанализируем причины возникновения таких сложностей, рассмотрим историю развития механизмов расширений в платформе 1С, найдем эффективные способы обхода ограничений на старых версиях платформы и разберем современные стандарты разработки.
Для того чтобы понять природу описываемых проблем, вернемся во времена платформ версий 8.3.12 – 8.3.15. В этот период механизм расширений активно развивался, но имел ряд серьезных архитектурных ограничений, заложенных на уровне ядра платформы.
Разработчики часто сталкивались со следующими ситуациями:
ЛюбаяСсылка. При добавлении собственного справочника в расширение и попытке сослаться на него из реквизитов основной конфигурации или использовать его в универсальных механизмах возникала ошибка. Техническая поддержка 1С объясняла это тем, что типы, привносимые расширениями, не входят в системные обобщенные типы данных (такие как ЛюбаяСсылка, СправочникСсылка или ДокументСсылка). Это было плановым ограничением архитектуры расширений первого поколения..epf) или внешнего отчета (файл .erf) разработчик запускал Конструктор запросов, но не обнаруживал в списке доступных таблиц новые справочники, документы или регистры сведений, созданные в расширении. При этом ручной текст запроса, написанный по правилам обращения к этим объектам, успешно выполнялся платформой в режиме «1С:Предприятие».Проанализируем, как фирма «1С» последовательно решала эти проблемы в новых релизах платформы, и как нам следует писать код сегодня.
Если вы работаете на актуальных версиях платформы, многие из проблем, обсуждавшихся на форумах несколько лет назад, для вас уже неактуальны благодаря системным доработкам платформы.
Начиная с версии платформы 8.3.20, фирма «1С» полностью сняла ограничение на вхождение типов расширений в обобщенные типы. Теперь типы данных, созданные в расширениях (например, ссылки на новые справочники или документы), автоматически интегрируются в системные типы ЛюбаяСсылка, СправочникСсылка, ДокументСсылка и другие. Системные методы, такие как Справочники.ТипВсеСсылки().Типы(), теперь корректно возвращают типы объектов как основной конфигурации, так и всех активных расширений. Это существенно упростило разработку и позволило бесшовно интегрировать расширения с механизмами Библиотеки стандартных подсистем (БСП).
Долгое время Конструктор запросов во внешних файлах не имел доступа к пространству имен расширений. Начиная с версии 8.3.28, это ограничение было полностью устранено. Теперь при разработке внешних отчетов и обработок в режиме Конфигуратора:
Если ваша база работает на платформе версии 8.3.28 и выше, вы можете вести разработку стандартными методами, не прибегая к ухищрениям.
Если на вашем предприятии или у клиента используется старая версия платформы (ниже 8.3.20 или 8.3.28) и обновить ее в ближайшее время невозможно, вам пригодятся проверенные временем практические приемы.
Выясним важную деталь: СУБД физически создает таблицы под новые объекты расширения в базе данных (присваивая им внутренние имена с суффиксами). Платформа 1С на уровне исполнения прекрасно знает эти таблицы. Следовательно, если Конструктор запросов выдает ошибку или "не видит" таблицу, мы можем написать текст запроса вручную в текстовом редакторе модуля.
Рассмотрим пример обращения к новому регистру сведений ВоенныйУчетСотрудников, созданному в расширении, из внешней обработки:
// Пример ручного написания запроса к объекту расширения
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВоенныйУчет.Сотрудник КАК Сотрудник,
| ВоенныйУчет.Военкомат КАК Военкомат,
| ВоенныйУчет.НомерБилета КАК НомерБилета
|ИЗ
| РегистрСведений.ВоенныйУчетСотрудников КАК ВоенныйУчет
|ГДЕ
| ВоенныйУчет.Активен = &Активен";
Запрос.УстановитьПараметр("Активен", Истина);
РезультатЗапроса = Запрос.Выполнить();
ТаблицаДанных = РезультатЗапроса.Выгрузить();
Этот код отработает без ошибок в режиме «1С:Предприятие», несмотря на то, что визуальный Конструктор запросов во внешней обработке на старой платформе будет подчеркивать имя регистра красным цветом или сообщать об ошибке синтаксиса.
Стандартная Консоль запросов, запускаемая как внешняя обработка (.epf), работает в контексте основной конфигурации. По этой причине она не видит метаданные расширений. Решением является использование специальных инструментов разработчика, которые внедряются непосредственно в саму базу в виде расширения конфигурации (файл с расширением .cfe).
Поскольку такая консоль компилируется внутри пространства имен самого расширения, ее внутренний Конструктор запросов получает полный доступ ко всем добавленным справочникам, документам и регистрам. Вы сможете без проблем конструировать запросы визуально и выбирать параметры любых типов.
Если вам необходимо передавать ссылки на новые объекты расширения в универсальные модули или хранить их в реквизитах основной конфигурации, где тип ограничен стандартным набором, используйте механизм сериализации (преобразования в строку). Разберем по шагам, как это реализовать.
Вместо прямой ссылки мы будем хранить два строковых значения: уникальный идентификатор ссылки и полное имя типа метаданных. Посмотрим на пример кода:
// Шаг 1. Сохранение ссылки объекта расширения в строковые реквизиты
Процедура СохранитьСсылкуРасширения(ОбъектПриемник, СсылкаНаОбъектРасширения)
// Получаем уникальный идентификатор ссылки в виде GUID строки
ОбъектПриемник.ДопИдентификаторСтрока = XMLСтрока(СсылкаНаОбъектРасширения);
// Получаем полное имя типа метаданных (например, "Справочник.МойСправочникИзРасширения")
ОбъектПриемник.ДопТипДанныхСтрока = СсылкаНаОбъектРасширения.Метаданные().ПолноеИмя();
КонецПроцедуры
// Шаг 2. Восстановление прямой ссылки из строковых реквизитов
Функция ВосстановитьСсылкуРасширения(ОбъектИсточник) Экспорт
ИмяТипа = ОбъектИсточник.ДопТипДанныхСтрока;
GUIDСтрока = ОбъектИсточник.ДопИдентификаторСтрока;
Если ПустаяСтрока(GUIDСтрока) Или ПустаяСтрока(ИмяТипа) Тогда
Возврат Неопределено;
КонецЕсли;
// Формируем тип данных динамически
ТипОбъекта = Тип(ИмяТипа + "Ссылка");
// Восстанавливаем ссылку по типу и GUID
Попытка
Возврат XMLЗначение(ТипОбъекта, GUIDСтрока);
Исключение
ЗаписьЖурналаРегистрации("Расширение.ВосстановлениеСсылки",
УровеньЖурналаРегистрации.Ошибка,,,
ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
КонецФункции
Этот подход гарантирует стабильную работу логики на абсолютно любых версиях платформы 1С v8.3, предотвращая появление ошибок несоответствия типов данных.
Часто в процессе разработки возникает необходимость не просто создать новый объект, но и связать его работу с бизнес-логикой существующих документов или справочников. Для этого мы заимствуем модули оригинальной конфигурации в расширение.
Разберем основные правила и механизмы модификации кода в расширении с использованием аннотаций (директив препроцессора):
&Вместо. Полностью замещает оригинальный метод конфигурации. Внутри метода-перехватчика мы можем использовать конструкцию ПродолжитьВызов(), чтобы передать управление исходной процедуре или функции после выполнения нашего кода или до него.&Перед. Наш метод выполняется строго до вызова оригинального метода конфигурации. Это удобно для валидации данных или предварительной подготовки параметров.&После. Наш метод выполняется сразу после отработки оригинального метода. Отлично подходит для постобработки результатов работы алгоритма.Посмотрим на практический пример доработки проведения документа в расширении для выполнения движений по нашему новому регистру сведений:
&После("ОбработкаПроведения")
Процедура Расш1_ОбработкаПроведения(Отказ, РежимПроведения)
// Если проведение уже отклонено базовым алгоритмом, не выполняем лишних действий
Если Отказ Тогда
Возврат;
КонецЕсли;
// Пишем данные в наш регистр сведений из расширения
НаборЗаписей = РегистрыСведений.ВоенныйУчетСотрудников.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(Ссылка);
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Период = Дата;
НоваяЗапись.Сотрудник = ЭтотОбъект.Ссылка.Сотрудник; // Обращаемся к реквизиту базового документа
НоваяЗапись.Активен = Истина;
Попытка
НаборЗаписей.Записать();
Исключение
Отказ = Истина;
ВызватьИсключение "Ошибка записи в дополнительный регистр расширения: " + ОписаниеОшибки();
КонецПопытки;
КонецПроцедуры
При доработке процедур в модулях форм необходимо помнить следующие правила:
&НаКлиенте или &НаСервере) в расширяющем методе должны строго совпадать с директивами исходного метода основной конфигурации. В противном случае платформа проигнорирует перехват метода, и код расширения выполняться не будет.&Вместо, сохраняя оригинальную сигнатуру параметров метода.Соблюдение этих правил и понимание архитектурных особенностей платформы позволят вам создавать надежные, стабильные расширения конфигурации, которые легко перенесут обновления основной конфигурации и сохранят работоспособность на любых релизах платформы «1С:Предприятие 8.3».