Потребовалось написать отчет, где пользователь на форме задает ряд отборов и параметров, получает на форме некоторую таблицу, модифицирует ее, на ее основе с теми же отборами получает основной отчет. Можно полностью написать свою форму отчета, но пользователь скорее всего потребует привычный функционал из БСП, к которому он уже привык, такой как подсчет суммы ячеек, сворачивание групп, открытие стандартной формы настройки и т.д.
Проше всего в отчет скопировать стандартную форму отчета из БСП (по умолчанию она и так вызывается из любого отчета на СКД) и модифицировать ее соответствующим образом. К тому же в моем случае это решает еще одну проблему. Я так и не нашел корректного способа передать таблицу из клиента из формы на сервер в фоновое задание, где по умолчанию выполняется компоновка всех отчетов, встроенных в конфигурацию. Для внешних отчетов все работает хорошо, при встраивании конфигурацию вместо таблицы возвращается null. Подозреваю – недоработка 1с. Выход из ситуации - производить компоновку прямо из формы. Если кто-нибудь решил эту проблему другим способом, дайте пожалуйста знать в комментариях.
Итак, модифицируем наш отчет:
В общий модуль вставим несколько функций, которые будем использовать и заглушку, что-б не вызывалась стандартная функция компоновки:
//Важно!!!!! Код компоновки результата находится в модуле форм
Функция ПолучитьПользовательскийПараметр(ИмяПараметра, КомпоновщикНастроек) Экспорт
НайденныйПараметр = Неопределено;
НайденныйПараметрВарианта = КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы.Найти(ИмяПараметра);
Если НайденныйПараметрВарианта <> Неопределено Тогда
НайденныйПараметр = ПолучитьПредопределенныйЭлементПользовательскихНастроек(НайденныйПараметрВарианта, КомпоновщикНастроек.ПользовательскиеНастройки);
КонецЕсли;
Возврат НайденныйПараметр;
КонецФункции
Функция ПолучитьПредопределенныйЭлементПользовательскихНастроек(ЭлементНастроекВарианта, ПользовательскиеНастройки) Экспорт
НайденныйЭлемент = Неопределено;
Если ЭлементНастроекВарианта <> Неопределено Тогда
НайденныйЭлемент = ПользовательскиеНастройки.Элементы.Найти(ЭлементНастроекВарианта.ИдентификаторПользовательскойНастройки);
КонецЕсли;
Возврат НайденныйЭлемент;
КонецФункции
Процедура ОпределитьНастройкиФормы(Форма, КлючВарианта, Настройки) Экспорт
//Настройки.События.ПриСозданииНаСервере = Истина;
КонецПроцедуры
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка=Ложь;
КонецПроцедуры
//Важно!!!!! Код компоновки результата находится в модуле формы
Добавляем на форму отчета, скопированную из общих форм, нашу таблицу цен и кнопку для ее заполнения. Пропишем код на форме:
&НаСервере
Процедура ЗаполнитьЦеныНаСервере()
ОтчетОбъект = РеквизитФормыВЗначение("Отчет");
СхемаЗаполненияЦен = ОтчетОбъект.ПолучитьМакет("СхемаЗаполненияЦен");
НастройкиСхемаЗаполненияЦен = СхемаЗаполненияЦен.НастройкиПоУмолчанию;
ПараметрыДанныхСхемаЗаполненияЦен = НастройкиСхемаЗаполненияЦен.ПараметрыДанных.Элементы;
ИспользоватьСпециальныйПрайсПараметр = ОтчетОбъект.ПолучитьПользовательскийПараметр("ИспользоватьСпециальныйПрайс", ОтчетОбъект.КомпоновщикНастроек);
ИспользоватьСпециальныйПрайсПараметр2= ПараметрыДанныхСхемаЗаполненияЦен.Найти("ИспользоватьСпециальныйПрайс");
ЗаполнитьЗначенияСвойств(ИспользоватьСпециальныйПрайсПараметр2,ИспользоватьСпециальныйПрайсПараметр,"Использование,Значение");
СпециальныйПрайсПараметр = ОтчетОбъект.ПолучитьПользовательскийПараметр("СпециальныйПрайс", ОтчетОбъект.КомпоновщикНастроек);
СпециальныйПрайсПараметр2= ПараметрыДанныхСхемаЗаполненияЦен.Найти("СпециальныйПрайс");
ЗаполнитьЗначенияСвойств(СпециальныйПрайсПараметр2,СпециальныйПрайсПараметр,"Использование,Значение");
ПериодОтчетаПараметр = ОтчетОбъект.ПолучитьПользовательскийПараметр("ПериодОтчета", ОтчетОбъект.КомпоновщикНастроек);
ЭлементНачалоПериода = ПараметрыДанныхСхемаЗаполненияЦен.Найти("ДатаНачала");
ЭлементНачалоПериода.Использование = Истина;
ЭлементНачалоПериода.Значение = ПериодОтчетаПараметр.Значение.ДатаНачала;
ЭлементКонецПериода = ПараметрыДанныхСхемаЗаполненияЦен.Найти("ДатаОкончания");
ЭлементКонецПериода.Использование = Истина;
ЭлементКонецПериода.Значение = ПериодОтчетаПараметр.Значение.ДатаОкончания;
КомпоновщикНастроекДанных = Новый КомпоновщикНастроекКомпоновкиДанных;
КомпоновщикНастроекДанных.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(СхемаЗаполненияЦен));
КомпоновщикНастроекДанных.ЗагрузитьНастройки(СхемаЗаполненияЦен.НастройкиПоУмолчанию);
КомпоновщикНастроекДанных.ЗагрузитьПользовательскиеНастройки(Отчет.КомпоновщикНастроек.ПользовательскиеНастройки);
//Копируем элементы отбора
КомпоновщикНастроекДанных.Настройки.Отбор.Элементы.Очистить();
Для Каждого ЭлементНастроек Из Отчет.КомпоновщикНастроек.ПользовательскиеНастройки.Элементы Цикл
Если ТипЗнч(ЭлементНастроек)=Тип("ЭлементОтбораКомпоновкиДанных") И ЭлементНастроек.Использование Тогда
НовСтрока=КомпоновщикНастроекДанных.Настройки.Отбор.Элементы.Добавить(ТипЗнч(ЭлементНастроек));
ЭлОтбораООНайден=Ложь;
Для Каждого ЭлОтбораОО из Отчет.КомпоновщикНастроек.Настройки.Отбор.Элементы цикл
Если ЭлОтбораОО.ИдентификаторПользовательскойНастройки = ЭлементНастроек.ИдентификаторПользовательскойНастройки Тогда
ЭлОтбораООНайден=Истина;
Прервать;
КонецЕсли;
КонецЦикла;
Если ЭлОтбораООНайден Тогда
ЗаполнитьЗначенияСвойств(НовСтрока,ЭлОтбораОО,"ЛевоеЗначение");
ЗаполнитьЗначенияСвойств(НовСтрока,ЭлементНастроек,"ВидСравнения,ПравоеЗначение,Использование");
КонецЕсли;
КонецЕсли;
КонецЦикла;
КомпоновщикМакетаСхемаЗаполненияЦен = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновкиДанных = КомпоновщикМакетаСхемаЗаполненияЦен.Выполнить(СхемаЗаполненияЦен, КомпоновщикНастроекДанных.ПолучитьНастройки(),,,Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
// Инициализация процессора компоновки
ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновкиДанных,,,);
ТаблицаЦенНовая= Новый ТаблицаЗначений;
// Получение результата
ПроцессорВыводаРезультатаКомпоновкиДанных = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ПроцессорВыводаРезультатаКомпоновкиДанных.УстановитьОбъект(ТаблицаЦенНовая);
ПроцессорВыводаРезультатаКомпоновкиДанных.Вывести(ПроцессорКомпоновкиДанных);
Отчет.ТаблицаЦен.Загрузить(ТаблицаЦенНовая);
КонецПроцедуры
&НаКлиенте
Процедура ЗаполнитьЦены(Команда)
ЗаполнитьЦеныНаСервере();
КонецПроцедуры
Теперь, входим в настройки формы и через состав команд отключаем стандартную кнопку “Сформировать”. Создаем свою команду “Сформировать” , отображаем ее на том же месте и прописываем для нее код:
&НаСервере
Процедура СформироватьОтчетНаСервере(ТабдДок)
ОбъектОтчет = РеквизитФормыВЗначение("Отчет");
ТабдДок=Новый ТабличныйДокумент;
// Создаем МВТ
МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
// Заполняем таблицу в МВТ
ТаблицаЦенКопия=Отчет.ТаблицаЦен.Выгрузить();
Запрос =Новый Запрос;
Запрос.МенеджерВременныхТаблиц= МенеджерВременныхТаблиц;
Запрос.Текст =
"ВЫБРАТЬ
| ТабЦен.Номенклатура КАК Номенклатура,
| ТабЦен.Цена КАК Цена
|ПОМЕСТИТЬ ТЦен
|ИЗ
| &ТабЦен КАК ТабЦен
|ГДЕ
| ТабЦен.Цена <> ТабЦен.ЦенаДоРедактирования";
Запрос.УстановитьПараметр("ТабЦен",ТаблицаЦенКопия);
РезультатЗапроса = Запрос.Выполнить();
// Получает табличный документ
Настройки = ОбъектОтчет.КомпоновщикНастроек.ПолучитьНастройки();
НужноОбъединятьЯчейкиПараметр = Настройки.ПараметрыДанных.Элементы.Найти("НужноОбъединятьЯчейки");
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
ДанныеРасшифровки = Новый ДанныеРасшифровкиКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(ОбъектОтчет.СхемаКомпоновкиДанных,Настройки,ДанныеРасшифровки);
ВнешниеНаборыДанных = Новый Структура;
//ВнешниеНаборыДанных.Вставить("ТЗДанных",ТЗДанных);
ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки,ВнешниеНаборыДанных,ДанныеРасшифровки,,,МенеджерВременныхТаблиц);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ТабдДок);
ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных);
Если НужноОбъединятьЯчейкиПараметр.Значение Тогда
ТабдДок = ОбработатьЗаголовки(ТабдДок);
КонецЕсли;
// Заполняем специальную структуру для дальнейшего вывода табличного документа стандартными средствами БСП
Результат=Новый Структура;
Результат.Вставить("Успех",Истина);
Результат.Вставить("ТекстОшибки","");
Результат.Вставить("Расшифровка",ДанныеРасшифровки);
Результат.Вставить("ТабличныйДокумент",ТабдДок);
// Отображаем документ
ОтчетыКлиентСервер.ОтобразитьСостояниеОтчета(ЭтотОбъект);
ЗаполнитьЗначенияСвойств(НастройкиОтчета.Печать, ОтчетТабличныйДокумент); // Сохранение настроек печати.
ОтчетТабличныйДокумент = Результат.ТабличныйДокумент;
ЗаполнитьЗначенияСвойств(ОтчетТабличныйДокумент, НастройкиОтчета.Печать); // Восстановление.
Если ЗначениеЗаполнено(ОтчетДанныеРасшифровки) И ЭтоАдресВременногоХранилища(ОтчетДанныеРасшифровки) Тогда
УдалитьИзВременногоХранилища(ОтчетДанныеРасшифровки);
КонецЕсли;
ОтчетДанныеРасшифровки = ПоместитьВоВременноеХранилище(Результат.Расшифровка, УникальныйИдентификатор);
Результат.Вставить("ИмяСобытия", "ПослеФормирования");
Результат.Вставить("Непосредственно", Ложь);
ОбновитьЭлементыФормыНастроекНаСервере(Результат);
КонецПроцедуры
Функция ПолучитьТаблицуЦен()
Возврат Отчет.ТаблицаЦен.Выгрузить();
КонецФункции
&НаСервереБезКонтекста
Функция ОбъединятьЯчейки(ТабДок, индСтр, индКол)
Ячейка = ТабДок.Область(индСтр, индКол);
ЯчейкаСлед = ТабДок.Область(индСтр, индКол+1);
Если ПустаяСтрока(Ячейка.Текст) Тогда
Возврат ложь
ИначеЕсли
Ячейка.Текст = ЯчейкаСлед.Текст
И Ячейка.Верх = Ячейка.Низ И ЯчейкаСлед.Верх = ЯчейкаСлед.Низ Тогда
Возврат Истина;
Иначе
Возврат ложь
КонецЕсли;
КонецФункции
&НаСервереБезКонтекста
Функция ОбработатьЗаголовки(ТабДок)
ВысотаФ = ТабДок.ФиксацияСверху;
ШиринаФ = ТабДок.ФиксацияСлева;
ОбъединяемаяОбласть = Неопределено;
СписокТипов=Новый СписокЗначений;
Для индСтр = -ВысотаФ По -1 Цикл
//Если ТабДок.Область(-индСтр,1).Текст = "" Тогда
// Возврат ТабДок;
//КонецЕсли;
НачальнаяКолонка = 0; СчетчикНО=0; СчетчикКО=0;
Для индКол=ШиринаФ+1 По ТабДок.ШиринаТаблицы Цикл
Если -индСтр=ВысотаФ-2 И ТабДок.Область(-индСтр, индКол).Текст="" Тогда
ТабДок.Область(ВысотаФ-2, индКол).Текст=ТабДок.Область(ВысотаФ, индКол).Текст;
ОбъединяемаяОбласть = ТабДок.Область(ВысотаФ-2, индКол, ВысотаФ, индКол);
ОбъединяемаяОбласть.Объединить();
ОбъединяемаяОбласть.РазмещениеТекста=ТипРазмещенияТекстаТабличногоДокумента.Переносить;
ИначеЕсли ТабДок.Область(-индСтр, индКол).Текст="Сумма ДР" Тогда
ОбъединяемаяОбласть = ТабДок.Область(-индСтр-1, индКол, -индСтр, индКол);
ОбъединяемаяОбласть.Объединить();
ИначеЕсли ОбъединятьЯчейки(ТабДок, -индСтр, индКол) Тогда
Если не НачальнаяКолонка Тогда
НачальнаяКолонка = индКол;
КонецЕсли;
ИначеЕсли НачальнаяКолонка Тогда
ТекстЗаголовка = ТабДок.Область(-индСтр, индКол).Текст;
ОбъединяемаяОбласть = ТабДок.Область(-индСтр, НачальнаяКолонка, -индСтр, индКол);
ОбъединяемаяОбласть.Объединить();
ОбъединяемаяОбласть.ГоризонтальноеПоложение = ГоризонтальноеПоложение.Центр;
ОбъединяемаяОбласть.Текст = ТекстЗаголовка;
НачальнаяКолонка = 0;
Иначе
НачальнаяКолонка = 0;
КонецЕсли;
КонецЦикла;
КонецЦикла;
Возврат ТабДок;
КонецФункции
В моем случае, дополнительно потребовалось объединить одинаковые заголовки ячеек для красоты
Полезные ссылки:
Другие разработки автора:
Акция! Вы можете скачать архив всех моих разработок, которые я предлагаю за StartMone, по Специальной цене: //infostart.ru/public/960899/#archive
PS: Надеюсь вам понравится эта и другие мои разработки на //infostart.ru/profile/48714/.
Очень жду ваших комментариев и пожеланий.
Молочников Олег Spb. 2024.