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