Молочников Олег Spb. 2024
Хитрости создания расширений для конфигураций на БСП. Часть 3.
Первая часть статьи здесь: //infostart.ru/1c/articles/996052/
Вторая часть статьи здесь: //infostart.ru/1c/articles/1044424/
Рассмотрим на примере доработки уже знакомого по первой части расширения: Подсистема "Входной контроль" в 1С:ERP/КА/УТ
Первым делом доработаем механизм БСП Связанные документы, чтобы у нас корректно работала общая форма "Связанные документы", доступная из меню Отчеты документов. Нужно сделать так, чтобы не испоганить типовой механизм, и сделать так, чтобы другие расширения, если они тоже будут его менять, работали корректно. Не забудьте, в первой части мы проделали предварительную работу для работы механизма создания на основании и подключили механизм подключаемых команд и отчетов БСП к нашим новым документам.
1. Создадим свой критерий отбора в расширении
В тип включим все документы, которые мы затащили в расширение, на основании которых будут создаваться документы в расширении и сами новые документы.
В составе документы в расширении, и дополнительно указываем реквизиты для связи:
Затягиваем в расширение общий модуль СтруктураПодчиненностиСлужебный и добавляем код:
&Вместо("ИндексТиповСвязанныхОбъектов")
Функция ВК_ИндексТиповСвязанныхОбъектов1()
// Вставить содержимое метода.
Индекс = ПродолжитьВызов();
МетаданныеСвязанныхОбъектов = Метаданные.КритерииОтбора.мо_СвязанныеДокументы;
ТипыСвязанныхОбъектов = МетаданныеСвязанныхОбъектов.Тип.Типы();
ТипПараметраКоманды = Метаданные.ОбщиеКоманды.СвязанныеДокументы.ТипПараметраКоманды;
Для Каждого ТипСвязанногоОбъекта Из ТипыСвязанныхОбъектов Цикл
Если Не ТипПараметраКоманды.СодержитТип(ТипСвязанногоОбъекта) Тогда
Индекс.Вставить(ТипСвязанногоОбъекта, Истина);
КонецЕсли;
КонецЦикла;
Возврат Индекс;
КонецФункции
Затягиваем в расширение общую форму СвязанныеДокументы и добавляем код:
&НаСервере
&Вместо("ОбъектыПоКритериюОтбора")
Функция ВК_ОбъектыПоКритериюОтбора(ЗначениеКритерияОтбора)
// Вставить содержимое метода.
СвязанныеКонф = ПродолжитьВызов(ЗначениеКритерияОтбора);
СвязанныеРасш = ВК2_ОбъектыПоКритериюОтбора(ЗначениеКритерияОтбора);
Результат = Новый ТаблицаЗначений;
Результат.Колонки.Добавить("Ссылка");
ОбщегоНазначенияКлиентСервер.ДополнитьТаблицу(СвязанныеКонф, Результат);
ОбщегоНазначенияКлиентСервер.ДополнитьТаблицу(СвязанныеРасш, Результат);
Возврат Результат;
КонецФункции
&НаСервере
Функция ВК2_ОбъектыПоКритериюОтбора(ЗначениеКритерияОтбора)
ШаблонЗапроса = "ВЫБРАТЬ РАЗРЕШЕННЫЕ
| ПредставлениеТаблицы.Ссылка КАК Ссылка
|ИЗ
| ИмяТаблицы КАК ПредставлениеТаблицы
|ГДЕ
| ПредставлениеТаблицы.ИмяРеквизита = &ЗначениеКритерияОтбора";
ШаблонЗапросаОбъединения = "ВЫБРАТЬ
| ПредставлениеТаблицы.Ссылка КАК Ссылка
|ИЗ
| ИмяТаблицы КАК ПредставлениеТаблицы
|ГДЕ
| ПредставлениеТаблицы.ИмяРеквизита = &ЗначениеКритерияОтбора";
ЧастиЗапроса = Новый Массив;
ТекстЧастиЗапроса = "";
Для Каждого ЭлементСостава Из Метаданные.КритерииОтбора.мо_СвязанныеДокументы.Состав Цикл
Если НЕ ЭлементСостава.Тип.СодержитТип(ТипЗнч(ЗначениеКритерияОтбора)) Тогда
Продолжить;
КонецЕсли;
ПутьКДанным = ЭлементСостава.ПолноеИмя();
Если СтрНайти(ПутьКДанным, "ТабличнаяЧасть") Тогда
ОбъектМетаданных = ЭлементСостава.Родитель().Родитель();
Иначе
ОбъектМетаданных = ЭлементСостава.Родитель();
КонецЕсли;
Если НЕ ПравоДоступа("Чтение", ОбъектМетаданных) Тогда
Продолжить;
КонецЕсли;
Точка = СтрНайти(ПутьКДанным, ".", НаправлениеПоиска.СКонца);
ИмяРеквизита = Сред(ПутьКДанным, Точка + 1);
ИмяТаблицы = ЭлементСостава.Родитель().ПолноеИмя();
ИмяТаблицы = СтрЗаменить(ИмяТаблицы, "ТабличнаяЧасть.", "");
Точка = СтрНайти(ИмяТаблицы, ".", НаправлениеПоиска.СКонца);
ПредставлениеТаблицы = Сред(ИмяТаблицы, Точка + 1);
ТекстЧастиЗапроса = ?(ТекстЧастиЗапроса = "", ШаблонЗапроса, ШаблонЗапросаОбъединения);
ТекстЧастиЗапроса = СтрЗаменить(ТекстЧастиЗапроса, "ИмяТаблицы", ИмяТаблицы);
ТекстЧастиЗапроса = СтрЗаменить(ТекстЧастиЗапроса, "ПредставлениеТаблицы", ПредставлениеТаблицы);
ТекстЧастиЗапроса = СтрЗаменить(ТекстЧастиЗапроса, "ИмяРеквизита", ИмяРеквизита);
ЧастиЗапроса.Добавить(ТекстЧастиЗапроса);
КонецЦикла;
Если ЧастиЗапроса.Количество() > 0 Тогда
Запрос = Новый Запрос;
Разделитель = Символы.ПС + "ОБЪЕДИНИТЬ" + Символы.ПС;
Запрос.Текст = СтрСоединить(ЧастиЗапроса, Разделитель);
Запрос.УстановитьПараметр("ЗначениеКритерияОтбора", ЗначениеКритерияОтбора);
Возврат Запрос.Выполнить().Выгрузить();
Иначе
Возврат Новый ТаблицаЗначений;
КонецЕсли;
КонецФункции
Смотрим результат:
-
Создадим печатную форму c макетом в виде word-документа, который может менять сам пользователь в пользовательском интерфейсе:
Предупреждение. На некоторых системах вывод в Word идет непозволительно долго. Дублируйте документ обычной печатной формой, чтоб у пользователя был выбор.
Найдем в конфигурации макеты, начинающиеся на «ПФ_DOC», выгрузим их содержимое в файлы с разрешением *.docx и найдем из них самый похожий на требуемый макет документа.
Адаптируем его под наши нужды, он будет выглядеть примерно вот так:
Скопируем любой из найденных макетов в наш документ и загрузим в него наш шаблон.
Затащим общий модуль УправлениеПечатьюУТКлиент в расширение, скопируем оттуда любую наиболее подходящую функцию вида мо_Печать_ИМЯДОКУМЕНТА_MicrosoftWord(ОписаниеКоманды) и переименуем ее в нашем случае в мо_Печать_АктВходногоКонтроляMicrosoftWord(ОписаниеКоманды), после чего адаптируем код под наши нужды.
Маленькая хитрость, для горизонтального положения листа вставьте код:
НастройкиМакета=Новый Соответствие;
НастройкиМакета.Вставить("Orientation",1);
ПечатнаяФорма = УправлениеПечатьюКлиент.ИнициализироватьПечатнуюФорму(ТипМакета,НастройкиМакета);
вместо
ПечатнаяФорма = УправлениеПечатьюКлиент.ИнициализироватьПечатнуюФорму(ТипМакета);
В модуль менеджера документа:
#Область Печать
// Заполняет список команд печати.
//
// Параметры:
// КомандыПечати - см. УправлениеПечатью.СоздатьКоллекциюКомандПечати
//
Процедура ДобавитьКомандыПечати(КомандыПечати) Экспорт
//---------
ИмяМакета = "ПФ_DOC_Акт" + "_" + ОбщегоНазначения.КодОсновногоЯзыка();
Если Метаданные.Документы.АктВыполненныхРабот.Макеты.Найти(ИмяМакета) <> Неопределено Тогда
// Акт выполненных работ (Microsoft Word)
КомандаПечати = КомандыПечати.Добавить();
КомандаПечати.Обработчик = "УправлениеПечатьюУТКлиент.мо_Печать_АктВходногоКонтроляMicrosoftWord";
КомандаПечати.МенеджерПечати = "";
КомандаПечати.Идентификатор = "АктMicrosoftWord";
КомандаПечати.Представление = НСтр("ru = 'Акт выполненных работ (Microsoft Word)';
|en = 'Customer invoice — Services (Microsoft Word)'");
КомандаПечати.ПроверкаПроведенияПередПечатью = Истина;
КомандаПечати.ТребуетсяРасширениеРаботыСФайлами = Истина;
КонецЕсли;
//---------
КонецПроцедуры
Функция ПолучитьДанныеПечати(знач МассивДокументов, знач МассивИменМакетов) Экспорт
Возврат Новый Структура("Данные,Макеты",
ПолучитьДанныеОбъектаПоМакетам(МассивДокументов, МассивИменМакетов),
ПолучитьМакетыИОписанияСекций(МассивИменМакетов));
КонецФункции
Функция ПолучитьДанныеОбъектаПоМакетам(знач МассивДокументов, знач МассивИменМакетов) Экспорт
ДанныеПоВсемОбъектам = Новый Соответствие;
СтруктураРезультатов = ПолучитьДанныеДляПечати(МассивДокументов, Неопределено);
ДанныеПечати = СтруктураРезультатов.РезультатПоШапке.Выбрать();
Пока ДанныеПечати.Следующий() Цикл
ДанныеОбъектаПоМакетам = Новый Структура;
ВыборкаПоСтрокамАК = СтруктураРезультатов.РезультатПоТабличнойЧасти.Выбрать();
ДанныеОбъекта = ПолучитьДанныеОбъектаПоВыборке(ДанныеПечати, ВыборкаПоСтрокамАК);
Для Каждого ИмяМакета Из МассивИменМакетов Цикл
ДанныеОбъектаПоМакетам.Вставить(ИмяМакета, ДанныеОбъекта);
КонецЦикла;
ДанныеПоВсемОбъектам.Вставить(ДанныеПечати.Ссылка, ДанныеОбъектаПоМакетам);
КонецЦикла;
Возврат ДанныеПоВсемОбъектам;
КонецФункции
Функция ПолучитьМакетыИОписанияСекций(знач МассивИменМакетов) Экспорт
ОписаниеСекций = Новый Структура;
ДвоичныеДанныеМакетов = Новый Структура;
Для Каждого ИмяМакета Из МассивИменМакетов Цикл
Макет = Неопределено;
ОписаниеСекцийМакета = Неопределено;
Если ИмяМакета = "ПФ_DOC_Акт" Тогда
ОписаниеСекцийМакета = ПолучитьОписаниеОбластейАктВыполненныхРабот();
Макет = УправлениеПечатью.МакетПечатнойФормы("Документ.мо_АктВходногоКонтроля.ПФ_DOC_Акт");
КонецЕсли;
Если ОписаниеСекцийМакета <> Неопределено И Макет <> Неопределено Тогда
ОписаниеСекций.Вставить(ИмяМакета, ОписаниеСекцийМакета);
ДвоичныеДанныеМакетов.Вставить(ИмяМакета, Макет);
КонецЕсли;
КонецЦикла;
Возврат Новый Структура(
"ОписаниеСекций,ДвоичныеДанныеМакетов",
ОписаниеСекций,
ДвоичныеДанныеМакетов);
КонецФункции
// Возвращает данные, необходимые для формирования печатных форм
//
// Параметры:
// МассивОбъектов - Массив - ссылки на объекты, которые нужно распечатать
// ПараметрыПечати - Структура - дополнительные настройки печати
//
// Возвращаемое значение:
// Структура - Содержит в себе данные по шапке документа и табличной части:
// * РезультатПоШапке - РезультатЗапроса -
// * РезультатПоТабличнойЧасти - РезультатЗапроса -
//
Функция ПолучитьДанныеДляПечати(МассивОбъектов, ПараметрыПечати) Экспорт
Запрос = Новый Запрос(
"ВЫБРАТЬ
| мо_АктВходногоКонтроля.Ссылка КАК Ссылка,
| мо_АктВходногоКонтроля.ВерсияДанных КАК ВерсияДанных,
| мо_АктВходногоКонтроля.ПометкаУдаления КАК ПометкаУдаления,
| мо_АктВходногоКонтроля.Номер КАК Номер,
| мо_АктВходногоКонтроля.Дата КАК Дата,
| мо_АктВходногоКонтроля.Проведен КАК Проведен,
| мо_АктВходногоКонтроля.ДокументОснование КАК ДокументОснование,
| мо_АктВходногоКонтроля.ДанныеАвтотранспорта КАК ДанныеАвтотранспорта,
| мо_АктВходногоКонтроля.ПроизводиласьЛиФотосьемкаПоставленногоСырья КАК ПроизводиласьЛиФотосьемкаПоставленногоСырья,
| мо_АктВходногоКонтроля.НачалоПриемки КАК НачалоПриемки,
| мо_АктВходногоКонтроля.ОкончаниеПриемки КАК ОкончаниеПриемки,
| мо_АктВходногоКонтроля.ПредставительОрганизации КАК ПредставительОрганизации,
| мо_АктВходногоКонтроля.ПредставительПоставщика КАК ПредставительПоставщика,
| мо_АктВходногоКонтроля.Комментарий КАК Комментарий,
| мо_АктВходногоКонтроля.Представление КАК Представление,
| мо_АктВходногоКонтроля.МоментВремени КАК МоментВремени,
| мо_АктВходногоКонтроля.ДокументОснование.ЗаказПоставщику.Номер КАК ЗаказПоставщикуНомер,
| мо_АктВходногоКонтроля.ДокументОснование.ЗаказПоставщику.Дата КАК ЗаказПоставщикуДата,
| мо_АктВходногоКонтроляТовары.Номенклатура.Производитель КАК Производитель,
| мо_АктВходногоКонтроля.ДокументОснование.Контрагент КАК Поставщик
|ИЗ
| Документ.мо_АктВходногоКонтроля.Товары КАК мо_АктВходногоКонтроляТовары
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.мо_АктВходногоКонтроля КАК мо_АктВходногоКонтроля
| ПО мо_АктВходногоКонтроляТовары.Ссылка = мо_АктВходногоКонтроля.Ссылка
| И (мо_АктВходногоКонтроляТовары.НомерСтроки = 1)
|ГДЕ
| мо_АктВходногоКонтроля.Ссылка В(&МассивДокументов)
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| мо_АктВходногоКонтроляТовары.Ссылка КАК Ссылка,
| мо_АктВходногоКонтроляТовары.НомерСтроки КАК НомерСтроки,
| мо_АктВходногоКонтроляТовары.НоменклатураПоставщика КАК НоменклатураПоставщика,
| мо_АктВходногоКонтроляТовары.Номенклатура КАК Номенклатура,
| мо_АктВходногоКонтроляТовары.Характеристика КАК Характеристика,
| мо_АктВходногоКонтроляТовары.Упаковка КАК Упаковка,
| мо_АктВходногоКонтроляТовары.КоличествоУпаковок КАК КоличествоУпаковок,
| мо_АктВходногоКонтроляТовары.Количество КАК Количество,
| мо_АктВходногоКонтроляТовары.Серия КАК Серия,
| мо_АктВходногоКонтроляТовары.СтатусУказанияСерий КАК СтатусУказанияСерий,
| мо_АктВходногоКонтроляТовары.НомерПаспорта КАК НомерПаспорта,
| мо_АктВходногоКонтроляТовары.КомментарийПоставщика КАК КомментарийПоставщика,
| мо_АктВходногоКонтроляТовары.КомментарийМенеджера КАК КомментарийМенеджера,
| мо_АктВходногоКонтроляТовары.НомерГТД КАК НомерГТД,
| мо_АктВходногоКонтроляТовары.Сертификат КАК Сертификат,
| мо_АктВходногоКонтроляТовары.КоличествоПровереннойПродукции КАК КоличествоПровереннойПродукции,
| мо_АктВходногоКонтроляТовары.КоличествоЗабракованнойПродукции КАК КоличествоЗабракованнойПродукции,
| мо_АктВходногоКонтроляТовары.КоличествоНекомплектнойПродукции КАК КоличествоНекомплектнойПродукции,
| мо_АктВходногоКонтроляТовары.ВидИспытания КАК ВидИспытания,
| мо_АктВходногоКонтроляТовары.мо_АктОНепрохождениеВходногоКонтроля КАК мо_АктОНепрохождениеВходногоКонтроля,
| мо_АктВходногоКонтроляТовары.НаличиеДокументов КАК НаличиеДокументов,
| мо_АктВходногоКонтроляТовары.Результат КАК Результат,
| мо_АктВходногоКонтроляТовары.ДатаОтбора КАК ДатаОтбора,
| мо_АктВходногоКонтроляТовары.ИмяСнимка КАК ИмяСнимка
|ИЗ
| Документ.мо_АктВходногоКонтроля.Товары КАК мо_АктВходногоКонтроляТовары
|ГДЕ
| мо_АктВходногоКонтроляТовары.Ссылка В(&МассивДокументов)
| И мо_АктВходногоКонтроляТовары.Результат = ЗНАЧЕНИЕ(Перечисление.мо_РезультатВходногоКонтроля.Несоответствует)");
Запрос.УстановитьПараметр("МассивДокументов", МассивОбъектов);
МассивРезультатов = Запрос.ВыполнитьПакет();
РезультатПоШапке = МассивРезультатов[0];
РезультатПоТабличнойЧасти = МассивРезультатов[1];
СтруктураДанныхДляПечати = Новый Структура("РезультатПоШапке, РезультатПоТабличнойЧасти",
РезультатПоШапке, РезультатПоТабличнойЧасти);
Возврат СтруктураДанныхДляПечати;
КонецФункции
Функция ПолучитьДанныеОбъектаПоВыборке(ДанныеПечати, ВыборкаПоСтрокамАК)
ДанныеОбъекта = Новый Структура;
ДанныеОбъекта.Вставить("ТекстЗаголовка", ОбщегоНазначенияУТКлиентСервер.СформироватьЗаголовокДокумента(ДанныеПечати, НСтр("ru = 'Акт';
|en = 'Customer invoice — Services'")));
Для Каждого КолонкаЗапроса из ДанныеПечати.Владелец().Колонки Цикл
ДанныеОбъекта.Вставить(КолонкаЗапроса.Имя);
КонецЦикла;
ЗаполнитьЗначенияСвойств(ДанныеОбъекта,ДанныеПечати);
ДанныеОбъекта.Вставить("СтрокиАК", Новый Массив);
//
ВыборкаПоСтрокамАК.Сбросить();
//
Пока ВыборкаПоСтрокамАК.Следующий() Цикл
НомерСтрокиПечать = "";
СтрокаТаблицыАК = Новый Структура;
Для Каждого КолонкаЗапроса из ВыборкаПоСтрокамАК.Владелец().Колонки Цикл
СтрокаТаблицыАК.Вставить(КолонкаЗапроса.Имя);
КонецЦикла;
ЗаполнитьЗначенияСвойств(СтрокаТаблицыАК,ВыборкаПоСтрокамАК);
ДанныеОбъекта.СтрокиАК.Добавить(СтрокаТаблицыАК);
КонецЦикла;
Возврат ДанныеОбъекта;
КонецФункции
Функция ПолучитьОписаниеОбластейАктВыполненныхРабот()
Секции = Новый Структура;
УправлениеПечатью.ДобавитьОписаниеОбласти(Секции, "ВерхнийКолонтитул", "ВерхнийКолонтитул");
//УправлениеПечатью.ДобавитьОписаниеОбласти(Секции, "НижнийКолонтитул", "НижнийКолонтитул");
УправлениеПечатью.ДобавитьОписаниеОбласти(Секции, "ЗаголовокДокумента", "Общая");
УправлениеПечатью.ДобавитьОписаниеОбласти(Секции, "ЗаголовокШапки", "Общая");
//УправлениеПечатью.ДобавитьОписаниеОбласти(Секции, "ДополнительнаяИнформацияШапки", "Общая");
//УправлениеПечатью.ДобавитьОписаниеОбласти(Секции, "Предложение", "Общая");
УправлениеПечатью.ДобавитьОписаниеОбласти(Секции, "ШапкаТаблицы", "СтрокаТаблицы");
УправлениеПечатью.ДобавитьОписаниеОбласти(Секции, "Строка", "СтрокаТаблицы");
УправлениеПечатью.ДобавитьОписаниеОбласти(Секции, "Подписи", "Общая");
//УправлениеПечатью.ДобавитьОписаниеОбласти(Секции, "ДополнительнаяИнформация", "Общая");
Возврат Секции;
КонецФункции
#КонецОбласти
Получаем результат:
Публикации автора (infostart.ru)