Нам часто требуется реализовать создание одного документа на основании другого в конфигурациях 1С, особенно если мы хотим избежать изменения типовой конфигурации и использовать расширения. Рассмотрим подробно, как реализовать создание объектов на основании других объектов, затрагивая различные аспекты от добавления команды до интеграции в структуру подчиненности и работы в безопасном режиме.
Мы можем добавить команду "Ввести на основании" несколькими способами, в зависимости от версии БСП (Библиотеки стандартных подсистем) и наших предпочтений.
Этот подход предполагает создание отдельной общей команды, которая будет отвечать за инициализацию нового документа.
Создаем новую Общую команду в расширении:
В конфигураторе, в расширении, в разделе Общие -> Общие команды, создадим новую команду.
Укажем для неё группу Командная панель формы.Создать на основании. Это критично для того, чтобы команда появилась в нужном подменю.
Тип параметра команды: выберем ссылки тех документов, в которых должна появиться новая строка в подменю ввода на основании (см. также методы доработки динамических списков). Например, если наш новый документ создается на основании РеализацииТоваровУслуг, то в типах параметра команды укажем ДокументСсылка.РеализацияТоваровУслуг.
Режим использования параметра: Одиночный.
Пишем код в модуле команды:
В процедуре ОбработкаКоманды модуля нашей команды пропишем код для открытия нового документа и передачи ему документа-основания. Это делается через структуру ЗначенияЗаполнения, которая будет передана в новый документ.
&НаКлиенте
Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)
// Создаем структуру для передачи данных заполнения в новый документ.
// "Основание" - это общепринятое имя параметра для документа-основания.
// Если требуется передать дополнительные данные, можем добавить их в эту структуру.
СтрДанные = Новый Структура("Основание", ПараметрКоманды);
ПараметрыФормы = Новый Структура("ЗначенияЗаполнения", СтрДанные);
// Открываем форму нового документа.
// Замените "Документ.Доверенность.ФормаОбъекта" на полный путь к форме вашего нового документа.
ОткрытьФорму("Документ.Доверенность.ФормаОбъекта", ПараметрыФормы, ПараметрыВыполненияКоманды.Источник, ПараметрыВыполненияКоманды.Уникальность, ПараметрыВыполненияКоманды.Окно, ПараметрыВыполненияКоманды.НавигационнаяСсылка);
КонецПроцедуры
Настраиваем права доступа:
Для того чтобы новая команда из расширения стала доступна пользователям, нам потребуется захватить или создать новую роль в расширении и включить в неё нашу созданную команду. Затем необходимо назначить эту роль соответствующим пользователям, предоставив им права на использование команды и на сам новый документ. Также полезно изучить пример внешней обработки ввода на основании документов — для этого подойдёт конструктор правил заполнения документов без изменения конфигурации.
Включаем команду в подсистему (при необходимости):
Если мы используем подсистемы для структурирования интерфейса, удостоверимся, что наша команда включена в нужную подсистему, чтобы она отображалась в пользовательском интерфейсе.
В современных версиях Библиотеки стандартных подсистем (БСП) процесс стал значительно проще, особенно если использовать справочник по методам БСП, и часто не требует создания отдельных общих команд. Мы можем модифицировать модуль менеджера документа, из которого хотим создавать новый документ, используя аннотации.
Захватываем модуль менеджера документа-основания:
В расширении захватываем модуль менеджера типового документа, из которого будет осуществляться ввод на основании. Например, если мы создаем документ на основании РеализацииТоваровУслуг, захватываем модуль менеджера именно этого документа.
Переопределяем процедуру ДобавитьКомандыСозданияНаОсновании:
В модуле менеджера документа-основания мы используем аннотацию &После или &Вместо для процедуры ДобавитьКомандыСозданияНаОсновании. Важно: если процедура ДобавитьКомандуСоздатьНаОсновании уже существует в модуле менеджера вашего нового документа расширения, достаточно использовать &После, чтобы добавить нашу команду к списку существующих. Если же нам нужно полностью переопределить список команд (например, скрыть типовые или добавить много своих), используем &Вместо.
Пример использования &После (для добавления нашей команды к существующим):
// В модуле менеджера документа, ИЗ КОТОРОГО создаем (захвачен в расширение)
&После("ДобавитьКомандыСозданияНаОсновании")
Процедура Расш_ДобавитьКомандыСозданияНаОсновании(КомандыСозданияНаОсновании, Параметры)
// Вызываем метод ДобавитьКомандуСоздатьНаОсновании для нашего нового документа.
// Замените "Документы.НакладнаяНаВнутреннееПеремещениеОС2" на ссылку на ваш новый документ.
Документы.НакладнаяНаВнутреннееПеремещениеОС2.ДобавитьКомандуСоздатьНаОсновании(КомандыСозданияНаОсновании);
КонецПроцедуры
Пример использования &Вместо (для полного контроля над списком команд, включая как типовые, так и наши):
// В модуле менеджера документа, ИЗ КОТОРОГО создаем (захвачен в расширение)
&Вместо("ДобавитьКомандыСозданияНаОсновании")
Процедура Расш1_ДобавитьКомандыСозданияНаОсновании(КомандыСозданияНаОсновании, Параметры)
// Создаем массив объектов, которые могут быть введены на основании
ОбъектыВводимыеНаОсновании = Новый Массив;
ОбъектыВводимыеНаОсновании.Добавить(Документы.ПриходныйКассовыйОрдер); // Пример типового документа
ОбъектыВводимыеНаОсновании.Добавить(Документы.НашНовыйДокументРасширения); // Замените на ссылку на ваш документ расширения
Для Каждого ОбъектВводимыйНаОсновании Из ОбъектыВводимыеНаОсновании Цикл
ОбъектВводимыйНаОсновании.ДобавитьКомандуСоздатьНаОсновании(КомандыСозданияНаОсновании);
КонецЦикла;
КонецПроцедуры
Убеждаемся, что в модуле менеджера нашего нового документа есть процедура ДобавитьКомандуСоздатьНаОсновании:
Если наш документ расширения является приемником, в его модуле менеджера должна быть экспортная процедура ДобавитьКомандуСоздатьНаОсновании. Эта процедура отвечает за добавление команды для создания на основании в контекстное меню. Если её нет, мы можем добавить её в расширении, захватив модуль менеджера нашего документа.
// В модуле менеджера НАШЕГО НОВОГО ДОКУМЕНТА (который создается на основании), захвачен в расширение
Процедура ДобавитьКомандуСоздатьНаОсновании(КомандыСозданияНаОсновании) Экспорт
// Добавляем команду для создания нашего документа
Команда = КомандыСозданияНаОсновании.Добавить();
Команда.Имя = "СоздатьНаОснованииНашНовыйДокумент"; // Уникальное имя команды
Команда.Представление = "Наш новый документ"; // Отображаемое имя в меню
Команда.Действие = "ОткрытьФормуДляСозданияНаОсновании"; // Имя процедуры-обработчика в этом же модуле менеджера
Команда.Порядок = 100; // Порядок отображения в меню
КонецПроцедуры
// Процедура-обработчик команды, которая будет открывать форму нового документа
Процедура ОткрытьФормуДляСозданияНаОсновании(Команда) Экспорт
// Здесь мы вызываем ОткрытьФорму с параметрами, аналогично Варианту 1
ПараметрыФормы = Новый Структура("ЗначенияЗаполнения", Команда.ПараметрКоманды);
ОткрытьФорму("Документ.НашНовыйДокумент.ФормаОбъекта", ПараметрыФормы, Команда.Источник, Команда.Уникальность, Команда.Окно, Команда.НавигационнаяСсылка);
КонецПроцедуры
Обратим внимание, что в БСП часто используется общий модуль Документы.ДобавитьКомандуСоздатьНаОсновании, который уже вызывает стандартную форму. Если этот механизм работает, нам достаточно лишь указать наш документ в списке, как показано в примерах с &После и &Вместо.
Если кнопка "Ввести на основании" все еще не появляется, рекомендуем проверить следующее — для этого пригодится профессиональный отладчик программного кода 1С:
После того как мы научились открывать форму нового документа, нам необходимо обеспечить его корректное заполнение на основе документа-основания (поможет универсальный инструмент заполнения реквизитов 1С без программирования). За это отвечает процедура ОбработкаЗаполнения в модуле объекта нашего нового документа.
Захватываем модуль объекта нашего документа:
В расширении захватываем модуль объекта того документа, который создается на основании (документ-приемник).
Переопределяем процедуру ОбработкаЗаполнения:
Используем аннотацию &После или &Перед для процедуры ОбработкаЗаполнения. Важно помнить, что параметр ДанныеЗаполнения может быть как прямой ссылкой на документ-основание, так и структурой, если мы передавали его через Новый Структура("Основание", ПараметрКоманды) из команды.
Рассмотрим, как правильно обработать параметр ДанныеЗаполнения, чтобы учесть оба варианта:
// В модуле объекта НАШЕГО НОВОГО ДОКУМЕНТА (захвачен в расширение)
&После("ОбработкаЗаполнения") // Или &Перед, в зависимости от того, хотим ли мы дополнить или полностью переопределить стандартное заполнение
Процедура Расш1_ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка)
// Шаг 1: Преобразование ДанныеЗаполнения, если оно пришло в виде структуры
Если ТипЗнч(ДанныеЗаполнения) = Тип("Структура") Тогда
// Проверяем наличие нашего ключа "Основание" в структуре
Если ДанныеЗаполнения.Свойство("Основание") Тогда
// Извлекаем ссылку на документ-основание из структуры для дальнейшей работы
ДанныеЗаполнения = ДанныеЗаполнения.Основание;
Иначе
// Если в структуре нет ожидаемого свойства, возможно, пришли другие параметры.
// В этом случае либо прекращаем обработку, либо обрабатываем другие параметры.
Возврат;
КонецЕсли;
КонецЕсли;
// Шаг 2: Теперь ДанныеЗаполнения должны быть ссылкой на документ-основание.
// Проверяем тип документа-основания
Если ТипЗнч(ДанныеЗаполнения) = Тип("ДокументСсылка.РеализацияТоваровУслуг") Тогда // Замените на тип вашего документа-основания
// Пример заполнения реквизитов нашего нового документа на основе документа-основания
Объект.Организация = ДанныеЗаполнения.Организация;
Объект.Контрагент = ДанныеЗаполнения.Контрагент;
Объект.СуммаДокумента = ДанныеЗаполнения.СуммаДокумента; // Если это уместно для вашего документа
Объект.Комментарий = "Документ заполнен на основании РеализацияТоваровУслуг №" + Строка(ДанныеЗаполнения.Номер) + " от " + Формат(ДанныеЗаполнения.Дата, "ДЛФ=Д");
// Если есть табличные части, переносим данные из них
Если ДанныеЗаполнения.Метаданные().ТабличныеЧасти.Содержит("Товары") Тогда // Пример: перенос табличной части "Товары"
Для Каждого ТекСтрокаТовары Из ДанныеЗаполнения.Товары Цикл
НоваяСтрока = Объект.Товары.Добавить(); // "Товары" - табличная часть нашего нового документа
НоваяСтрока.Номенклатура = ТекСтрокаТовары.Номенклатура;
НоваяСтрока.Количество = ТекСтрокаТовары.Количество;
НоваяСтрока.Цена = ТекСтрокаТовары.Цена;
НоваяСтрока.Сумма = ТекСтрокаТовары.Сумма;
// ... и так далее для других реквизитов табличной части
КонецЦикла;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
При необходимости, мы также можем использовать процедуру ЗаполнитьНаОсновании вместо ОбработкаЗаполнения, если нам нужна более специфичная логика заполнения, которая может быть вызвана не только из формы. Однако ОбработкаЗаполнения является стандартным механизмом платформы для таких случаев.
Подключение команды в модуле формы документа (если используется БСП):
Для корректной работы подключаемых команд в модуле формы самописного документа, использующего механизмы БСП, может потребоваться следующая процедура:
&НаКлиенте
Процедура Подключаемый_ВыполнитьКоманду(Команда)
ПодключаемыеКомандыКлиент.ВыполнитьКоманду(ЭтотОбъект, Команда, Объект);
КонецПроцедуры
Это одна из наиболее сложных частей задачи, поскольку типовые механизмы "Структуры подчиненности" (или "Связанные документы") часто глубоко интегрированы в конфигурацию и не всегда легко расширяются. Расширения не позволяют напрямую изменять состав критериев отбора, таких как КритерииОтбора.СвязанныеДокументы.Состав.
Этот подход требует значительных изменений, но дает полный контроль над логикой отображения связанных документов и является наиболее универсальным решением.
Изменяем общий модуль ВариантыОтчетовПереопределяемый:
Захватываем общий модуль ВариантыОтчетовПереопределяемый в расширение. Добавляем в него наш документ с помощью аннотации &После к процедуре ОпределитьОбъектыСКомандамиОтчетов. Это позволит системе знать о нашем документе при построении отчетов и структуры подчиненности.
// В общем модуле "ВариантыОтчетовПереопределяемый" (захваченном в расширение)
&После("ОпределитьОбъектыСКомандамиОтчетов")
Процедура Альфа_ОпределитьОбъектыСКомандамиОтчетов(Объекты) Экспорт
Объекты.Добавить(Метаданные.Документы.НашНовыйДокументРасширения); // Замените на ссылку на ваш документ расширения
КонецПроцедуры
Переопределяем общую форму СтруктураПодчиненности:
Захватываем общую форму СтруктураПодчиненности в расширение. В этой форме мы будем переопределять функции и процедуры, отвечающие за сбор связанных документов, чтобы добавить туда наши.
Функция ОбъектыПоКритериюОтбора (для получения подчиненных объектов):
Мы используем аннотацию &Вместо для функции ОбъектыПоКритериюОтбора. Внутри этой функции мы модифицируем запрос, чтобы включить в него наши документы расширения, которые связаны с документом-основанием.
// В модуле формы "СтруктураПодчиненности" (захваченной в расширение)
&Вместо("ОбъектыПоКритериюОтбора")
Функция Альфа_ОбъектыПоКритериюОтбора(ЗначениеКритерияОтбора)
Если Не Метаданные.КритерииОтбора.СвязанныеДокументы.Тип.СодержитТип(ТипЗнч(ЗначениеКритерияОтбора)) Тогда
Возврат Неопределено;
КонецЕсли;
УстановитьПривилегированныйРежим(Истина);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СвязанныеДокументы.Ссылка КАК Ссылка
|ИЗ
| КритерийОтбора.СвязанныеДокументы(&ЗначениеКритерияОтбора) КАК СвязанныеДокументы
|
|ОБЪЕДИНИТЬ ВСЕ
|
|ВЫБРАТЬ
| НашДокументРасширения.Ссылка
|ИЗ
| Документ.НашНовыйДокументРасширения КАК НашДокументРасширения
|ГДЕ
| НашДокументРасширения.ДокументОснование = &ЗначениеКритерияОтбора // Замените на ваш реквизит-ссылку на документ-основание
|
|ОБЪЕДИНИТЬ ВСЕ
|
|ВЫБРАТЬ
| НашДокументРасширения.Ссылка
|ИЗ
| Документ.НашНовыйДокументРасширения КАК НашДокументРасширения
|ГДЕ
| НашДокументРасширения.Заказ = &ЗначениеКритерияОтбора"; // Если есть другие связи, например, через реквизит "Заказ"
Запрос.УстановитьПараметр("ЗначениеКритерияОтбора", ЗначениеКритерияОтбора);
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
Здесь мы используем оператор ОБЪЕДИНИТЬ ВСЕ, чтобы к стандартному набору связанных документов добавить наши собственные. Важно: замените НашНовыйДокументРасширения на имя вашего документа в расширении и укажите реальные реквизиты, которые связывают его с документом-основанием (например, ДокументОснование, Заказ и т.д.).
Процедура ВывестиРодительскиеОбъекты (для получения родительских объектов):
Аналогично, переопределяем процедуру ВывестиРодительскиеОбъекты с помощью &Вместо, чтобы она корректно обрабатывала и наши документы расширения при построении дерева родительских связей. Эта процедура более сложна и требует тщательной адаптации.
// В модуле формы "СтруктураПодчиненности" (захваченной в расширение)
&Вместо("ВывестиРодительскиеОбъекты")
Процедура Альфа_ВывестиРодительскиеОбъекты(ТекущийОбъект, ДеревоРодитель)
СтрокиДерева = ДеревоРодитель.ПолучитьЭлементы();
МетаданныеОбъекта = ТекущийОбъект.Метаданные();
СписокРеквизитов = Новый СписокЗначений();
// Перебор всех реквизитов текущего объекта
Для Каждого Реквизит Из МетаданныеОбъекта.Реквизиты Цикл
// Добавляем проверку для нашего документа расширения
Если ТипЗнч(ТекущийОбъект) = Тип("ДокументСсылка.НашНовыйДокументРасширения") Тогда // Замените на тип вашего документа
// Здесь мы указываем, какие реквизиты нашего документа являются ссылками на родительские объекты.
Если Реквизит.Имя <> "ДокументОснование" И Реквизит.Имя <> "Заказ" Тогда // Имена реквизитов, связывающих с родителем
Продолжить;
КонецЕсли;
Иначе
// Для типовых документов сохраняем стандартную логику, но можем ее также расширить
Если Не Метаданные.КритерииОтбора.СвязанныеДокументы.Состав.Содержит(Реквизит) Тогда
Продолжить;
КонецЕсли;
КонецЕсли;
// Дальнейшая логика по извлечению значений реквизитов и добавлению их в список
Для Каждого ТекущийТип Из Реквизит.Тип.Типы Цикл
МетаданныеРеквизита = Метаданные.НайтиПоТипу(ТекущийТип);
Если МетаданныеРеквизита = Неопределено Тогда Продолжить; КонецЕсли;
Если Не ОбщегоНазначения.ОбъектМетаданныхДоступенПоФункциональнымОпциям(МетаданныеРеквизита) Или Не ПравоДоступа("Чтение", МетаданныеРеквизита) Тогда Продолжить; КонецЕсли;
Если Не Метаданные.Документы.Содержит(МетаданныеРеквизита) И Не Метаданные.Справочники.Содержит(МетаданныеРеквизита) И Не Метаданные.ПланыВидовХарактеристик.Содержит(МетаданныеРеквизита) Тогда Продолжить; КонецЕсли;
ЗначениеРеквизита = ТекущийОбъект[Реквизит.Имя];
Если ЗначениеЗаполнено(ЗначениеРеквизита) И ТипЗнч(ЗначениеРеквизита) = ТекущийТип И ЗначениеРеквизита <> ТекущийОбъект И СписокРеквизитов.НайтиПоЗначению(ЗначениеРеквизита) = Неопределено Тогда
ЯвляетсяДокументом = ОбщегоНазначения.ЭтоДокумент(МетаданныеРеквизита);
Если ЯвляетсяДокументом Тогда
СписокРеквизитов.Добавить(ЗначениеРеквизита, Формат(ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ЗначениеРеквизита, "Дата", Истина), "ДЛФ=DT"));
Иначе
СписокРеквизитов.Добавить(ЗначениеРеквизита, Дата(1,1,1));
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЦикла;
// Аналогичная обработка табличных частей для поиска родительских ссылок
Для Каждого ТЧ Из МетаданныеОбъекта.ТабличныеЧасти Цикл
ИменаРеквизитов = "";
СодержимоеТЧ = ТекущийОбъект[ТЧ.Имя].Выгрузить();
Для Каждого Реквизит Из ТЧ.Реквизиты Цикл
Если Не Метаданные.КритерииОтбора.СвязанныеДокументы.Состав.Содержит(Реквизит) Тогда Продолжить; КонецЕсли;
Для Каждого ТекущийТип Из Реквизит.Тип.Типы Цикл
МетаданныеРеквизита = Метаданные.НайтиПоТипу(ТекущийТип);
Если МетаданныеРеквизита = Неопределено Тогда Продолжить; КонецЕсли;
Если Не ОбщегоНазначения.ОбъектМетаданныхДоступенПоФункциональнымОпциям(МетаданныеРеквизита) Или Не ПравоДоступа("Чтение", МетаданныеРеквизита) Тогда Продолжить; КонецЕсли;
Если Не Метаданные.Документы.Содержит(МетаданныеРеквизита) И Не Метаданные.Справочники.Содержит(МетаданныеРеквизита) И Не Метаданные.ПланыВидовХарактеристик.Содержит(МетаданныеРеквизита) Тогда Продолжить; КонецЕсли;
ИменаРеквизитов = ИменаРеквизитов + ?(ИменаРеквизитов = "", "", ", ") + Реквизит.Имя;
Прервать;
КонецЦикла;
КонецЦикла;
СодержимоеТЧ.Свернуть(ИменаРеквизитов);
Для Каждого КолонкаТЧ Из СодержимоеТЧ.Колонки Цикл
Для Каждого СтрокаТЧ Из СодержимоеТЧ Цикл
ЗначениеРеквизита = СтрокаТЧ[КолонкаТЧ.Имя];
МетаданныеЗначения = Метаданные.НайтиПоТипу(ТипЗнч(ЗначениеРеквизита));
Если МетаданныеЗначения = Неопределено Тогда Продолжить; КонецЕсли;
Если Не ОбщегоНазначения.ОбъектМетаданныхДоступенПоФункциональнымОпциям(МетаданныеЗначения) Или Не ПравоДоступа("Чтение", МетаданныеЗначения) Тогда Продолжить; КонецЕсли;
Если ЗначениеРеквизита = ТекущийОбъект Или СписокРеквизитов.НайтиПоЗначению(ЗначениеРеквизита) <> Неопределено Тогда Продолжить; КонецЕсли;
ЯвляетсяДокументом = ОбщегоНазначения.ЭтоДокумент(МетаданныеЗначения);
Если Не ЯвляетсяДокументом И Не Метаданные.Справочники.Содержит(МетаданныеЗначения) И Не Метаданные.ПланыВидовХарактеристик.Содержит(МетаданныеЗначения) Тогда Продолжить; КонецЕсли;
Если ЯвляетсяДокументом Тогда
СписокРеквизитов.Добавить(ЗначениеРеквизита, Формат(ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ЗначениеРеквизита, "Дата", Истина), "ДЛФ=DT"));
Иначе
СписокРеквизитов.Добавить(ЗначениеРеквизита, Дата(1,1,1));
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецЦикла;
СписокРеквизитов.СортироватьПоПредставлению();
Для каждого ЭлементСписка Из СписокРеквизитов Цикл
Выборка = ПолучитьВыборкуПоРеквизитамОбъекта(ЭлементСписка.Значение);
Если Выборка.Следующий Тогда
СтрокаДерева = ДобавитьСтрокуВДерево(СтрокиДерева, Выборка);
Если НЕ ДобавляемыйОбъектИмеетсяСредиРодителей(ДеревоРодитель, ЭлементСписка.Значение) Тогда
ВывестиРодительскиеОбъекты(ЭлементСписка.Значение, СтрокаДерева);
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Этот код является более сложным и требует глубокого понимания логики формы СтруктураПодчиненности. Мы добавили условие для нашего документа расширения, чтобы определить, какие его реквизиты являются родительскими ссылками. Важно: адаптируйте этот код под специфику ваших документов и их связей.
Настройка состава критерия отбора:
В самой форме СтруктураПодчиненности, в элементах управления (например, таблицах или полях ввода), где используется критерий отбора СвязанныеДокументы, мы должны убедиться, что наш новый документ добавлен в список типов, по которым осуществляется отбор. Это делается в свойствах реквизитов формы или элементов управления, которые используют критерий отбора. Если это невозможно сделать напрямую через свойства в расширении, то подход с &Вместо на функциях формы будет единственным решением.
Если наш документ расширения является подчиненным к типовому документу, и у типового документа есть реквизит, выполняющий роль "документа-основания" (например, ДокументОснование, ЗаказКлиента и т.п.), мы можем попробовать добавить тип ссылки на наш документ расширения в типы значений этого типового реквизита. Этот подход значительно проще, но он применим только в следующих случаях:
Для добавления типа через расширение, захватите соответствующий реквизит типового документа в расширение и добавьте ваш документ расширения в список его типов. Это может потребовать изучения внутренней реализации типовой формы СтруктураПодчиненности для конкретной конфигурации, чтобы понять, какие реквизиты она использует для построения связей.
При работе в условиях 1С:Фреш или других средах, где активирован безопасный режим, стандартная процедура ОбработкаЗаполнения в модуле объекта документа расширения может не срабатывать из-за ограничений безопасности. В этом случае мы можем использовать альтернативный подход для заполнения документа.
Используем обработчик ПриСозданииНаСервереПосле в модуле формы документа:
В модуле формы нашего нового документа, который создается на основании, захватываем процедуру ПриСозданииНаСервереПосле. Этот обработчик выполняется на сервере после создания объекта, но до стандартной ОбработкаЗаполнения. Здесь мы можем вызвать собственную функцию для заполнения документа, минуя ограничения безопасного режима для ОбработкаЗаполнения.
// В модуле формы НАШЕГО НОВОГО ДОКУМЕНТА (захвачен в расширение)
&НаСервере
Процедура ДСПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
// Проверяем, был ли передан параметр "Основание" при открытии формы
Если Параметры.ЗначенияЗаполнения.Свойство("Основание") Тогда
// Вызываем нашу собственную функцию для заполнения документа
ЗаполнитьПоСчету(Параметры.ЗначенияЗаполнения.Основание);
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьПоСчету(ДокументОснование)
// Здесь размещаем всю логику заполнения реквизитов и табличных частей
// нашего документа на основании ДокументОснование.
// Пример:
Объект.Организация = ДокументОснование.Организация;
Объект.Контрагент = ДокументОснование.Контрагент;
// ... и т.д. заполнение всех необходимых реквизитов и табличных частей
// Например, перенос позиций товаров:
Если ДокументОснование.Метаданные().ТабличныеЧасти.Содержит("Товары") Тогда
Для Каждого СтрокаОснования Из ДокументОснование.Товары Цикл
НоваяСтрока = Объект.ТабличнаяЧастьНашегоДокумента.Добавить();
НоваяСтрока.Номенклатура = СтрокаОснования.Номенклатура;
НоваяСтрока.Количество = СтрокаОснования.Количество;
// ...
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Этот подход позволяет нам контролировать процесс заполнения документа в безопасном режиме, поскольку ПриСозданииНаСервере происходит до стандартной ОбработкаЗаполнения и предоставляет возможность инициализировать документ, минуя потенциальные ограничения.
Реализация создания документов на основании других через расширения в 1С — это мощный инструмент для кастомизации системы без изменения типовой конфигурации. Мы рассмотрели различные подходы к добавлению команды ввода на основании, заполнению документа и интеграции в механизмы связанных документов, а также особенности работы в безопасном режиме. Выбор конкретного метода будет зависеть от версии платформы, БСП, сложности требований и необходимости поддержания совместимости при обновлениях. Всегда старайтесь использовать наименее инвазивный метод, который соответствует вашим требованиям, чтобы облегчить поддержку и обновление конфигурации в будущем.