Делаем из СКД Excel (ну, почти)

02.03.20

Разработка - Работа с интерфейсом

Несложный в использовании способ внедрить в обычный отчет СКД возможность редактировать значения ресурсов отчета (а-ля Excel) и получать отредактированные значения для дальнейшей обработки.

Скачать исходный код

Наименование Файл Версия Размер
Делаем из СКД Excel (ну, почти):
.cf 22,72Kb
37
.cf 22,72Kb 37 Скачать

Решаемая проблема
Периодически у меня возникала следующая задача: необходимо было разработать некий расчетный инструмент или инструмент планирования, который рассчитывает на основании каких-то данных некие показатели, а пользователь должен иметь возможность при необходимости их скорректировать и зафиксировать в системе итоговый результат.
И в этот момент возникает проблема, поскольку этот инструмент с одной стороны является во многом аналитическим и должен предоставлять пользователю информацию для принятия решений в максимально удобной форме, а с другой стороны - должен позволять в удобном виде редактировать информацию и записывать ее в систему.
Для первого в 1С идеально подходит отчет СКД, а для второго - таблица на форме (источник данных для нее не особенно важен). Дилемма...
А самое страшное - у пользователей уже есть богатый опыт работы с инструментом, который объединяет удобную форму представления данных, алгоритмы расчета и сохранение этих данных. Это Excel - вечный укор одинэсникам :)
И пользователи искренне недоумевают, почему "в вашей программе" нельзя сделать также. И в самом деле - почему? :)


Принципы работы
Идея плавает на поверхности и на оригинальность не претендует. Некоторые из используемых решений компромиссные, имеется ряд ограничений.
В отчете СКД одна из группировок "назначается" ключевой (допустим, "Номенклатура"). Именно по ней пользователь будет редактировать значения ресурсов.
Возможна детализация этой группировки какой-то вертикальной группировкой (чаще всего необходима детализация по периоду).
Естественно, кроме ключевой горизонтальной группировки в отчете могут быть как вышестоящие, так и нижестоящие группировки (результаты по ключевой группировке можно хранить и получать в разрезе вышестоящих группировок).
Сразу после компоновки полученный результат отчета автоматически анализируется, определяется местонахождение нужных строк и колонок, значения ключевой группировки и ресурсов. Местонахождение колонок ресурсов производится по представлениям полей ресурсов в заголовке отчета либо по данным расшифровки (тогда их необходимо задать через макеты СКД). Значения ресурсов отчета также изначально берутся из текста ячеек.
Результат анализа со всеми полученными данными и их координатами фиксируется в отдельной структуре данных, где отражаются и все последующие изменения данных отчета. Когда пользователь редактирует на форме отчета значение любого из ресурсов ключевой группировки, эти изменения фиксируются в структуре данных (с возможным пересчетом связанных ячеек при необходимости - да-да, почти как в Excel). Редактирование происходит непосредственно в ячейках отчета (для этого после компоновки требуемые ячейки переоформляются на содержащие значения).
Поддерживается пересчет итогов по вышестоящим группировкам и общих вертикальных итогов. Пересчет горизонтальных итогов пока не предусмотрен.
Чтобы инструмент был максимально отзывчивым - количество серверных вызовов минимизировано. Непосредственно редактирование отчета серверных вызовов не производит.


Использование инструмента (или как сделать обычный отчет СКД - редактируемым)
Старался сделать внедрение минимально инвазивным
1) необходимо в ПриКомпоновкеРезультата добавить блок инициализации и настройки параметров редактируемого отчета (пример будет ниже)
2) на форме отчета необходимо в обработчик ПриИзмененииСодержимогоОбласти() добавить вызов одноименной процедуры (из общего модуля)

В принципе, это почти и все :)

Если необходимо добавить формулы для пересчета связанных ячеек – то одним из параметров при изменении содержимого области передается ссылка на свой обработчик, который будет вызываться после редактирования пользователем значения ресурса. В этом обработчике можно будет написать обычный код 1С по расчету связанных данных, после чего необходимо будет вызвать ПриИзмененииЗначенияРесурса() для отражения изменений (включая пересчет итогов). Эффект будет аналогичен экселевскому.
По-хорошему, не помешает в отчет добавить пару "красивостей", типа предупреждения о наличии измененных данных при попытке перекомпоновать или закрыть отчет (уже есть в прилагаемой демке)
Записать измененные данные в систему по команде пользователя не составляет никакой сложности, поскольку вот они - уже лежат структурированные в памяти (для удобства добавлена ПолучитьТаблицуРезультата(), позволяющая получать "слепок" данных отчета в привычную таблицу значений).

Пример настройки редактируемого отчета в ПриКомпоновкеРезультата (из демо-конфигурации):

// инициализация структуры редактируемого отчета и его настройка
СтруктураОтчета = РедактируемыеОтчетыСервер.ИнициализироватьСтруктуруОтчета(КомпоновщикНастроек, "Номенклатура", "Период"); // ключевые горизонтальная и вертикальная группировки
СтруктураОтчета.ДопГоризонтальныеГруппировки = Новый Структура("ГруппаНоменклатуры", Истина); // дополнительная вышестоящая группировка (с признаком пересчетом итогов по ней)
СтруктураОтчета.ИспользуютсяОбщиеВертикальныеИтогиВерх = Ложь;
СтруктураОтчета.ИспользуютсяОбщиеВертикальныеИтогиНиз = Истина;
	
// добавление в структуру отчета описания ресурсов
РедактируемыеОтчетыСервер.ДобавитьРесурсВСтруктуруОтчета(КомпоновщикНастроек, "Количество", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(12,1)), "ЧЦ=12; ЧДЦ=0", "Количество", Истина, Истина);
РедактируемыеОтчетыСервер.ДобавитьРесурсВСтруктуруОтчета(КомпоновщикНастроек, "Сумма", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(14,2)), "ЧЦ=14; ЧДЦ=2", "Сумма", Истина, Ложь);
	
// извлечение необходимых данных при компоновке отчета
РедактируемыеОтчетыСервер.ПриКомпоновкеРезультата(КомпоновщикНастроек, ДокументРезультат, ДанныеРасшифровки, СхемаКомпоновкиДанных, СтандартнаяОбработка);

Другие существующие на текущий момент возможности по дополнительной настройке редактируемого отчета можно посмотреть в процедуре ИнициализироватьСтруктуруОтчета()

Ограничения инструмента на текущий момент (те, что вспомнил)
1) редактирование ресурсов пока предусмотрено только для какой-то одной простой горизонтальной группировки (опционально с разверткой вправо по периодам или другой вертикальной группировке).
2) предполагается, что структура отчета СКД довольно стандартная. Горизонтальные группировки отчета выводятся в первой ячейке табличного документа (обычно так и бывает). Шапка отчета тоже сформирована стандартным образом (при анализе определяется местоположение шапки). Форматирование числовых ресурсов в отчете является стандартным в части возможности штатного преобразования строки в число.
3) пока предусмотрены только два типа редактируемых ресурсов - "Число" и "Дата". При этом ресурсы с пересчетом по вышестоящим группировкам могут быть только числовые.

Демо-конфигурация
В приложенной демо-конфигурации общая функциональность вынесена в общие модуля, что выглядит предпочитаемым способом использования.
Скачивать демо-конфигурацию за старт-мани вовсе не обязательно. Ниже привожу все функции/процедуры в полном объеме. Демка - просто удобный способ посмотреть на все это "добро" в действии. Демо-конфигурация выполнена на релизе 8.3.14 и приложена в виде файла cf для универсальности (тестовые данные в базе не содержатся).

После запуска демо-конфигурации необходимо открыть и сформировать демо-отчет. "Количество" в строках номенклатуры можно редактировать непосредственно. Нажатие кнопки "Вывести результат на экран" производит вывод через Сообщить() таблицы значений с отредактированными данными отчета.

Общий модуль "РедактируемыеОтчетыКлиент":

Процедура ПриИзмененииЗначенияРесурса(ФормаОтчета, НомерСтроки, ИмяРесурса, Знач СтароеЗначение, Знач НовоеЗначение, ИндексВертикальнойГруппировки = 0) Экспорт
	
	СтруктураОтчета = ФормаОтчета.Отчет.КомпоновщикНастроек.Настройки.ДополнительныеСвойства.СтруктураОтчета;
	ТабличныйДокумент = ФормаОтчета.Результат;
	
	Если СтароеЗначение = НовоеЗначение Тогда
		Возврат;
	КонецЕсли;
	
	СтруктураОтчета.СтрокиГоризонтальнойКлючевойГруппировки[НомерСтроки][ИмяРесурса][ИндексВертикальнойГруппировки] = НовоеЗначение;
	
	СтруктураОтчета.ДанныеИзменены = Истина;
	
	НомерКолонки = СтруктураОтчета.НомераКолонокРесурсов[ИмяРесурса][ИндексВертикальнойГруппировки];
	
	ФорматЗначения = СтруктураОтчета.ФорматыРесурсов[ИмяРесурса];
	Ячейка = ТабличныйДокумент.Область(НомерСтроки, НомерКолонки);
	Если Ячейка.Значение <> НовоеЗначение Тогда
		Ячейка.Значение = НовоеЗначение;
	КонецЕсли;
	Ячейка.ЦветФона = СтруктураОтчета.ЦветРедактированныхЯчеек;
	
	// пересчет итогов отчета
	Если СтруктураОтчета.РесурсыСПересчетомИтогов.Свойство(ИмяРесурса) Тогда
		
		// обновление общих итогов
		Если СтруктураОтчета.ИспользуютсяОбщиеВертикальныеИтогиВерх Тогда
			ЯчейкаОбщегоИтогаВерх = ТабличныйДокумент.Область(СтруктураОтчета.НомерСтрокиОбщихИтоговВерх, НомерКолонки);
			ЯчейкаОбщегоИтогаВерх.Значение = ЯчейкаОбщегоИтогаВерх.Значение + НовоеЗначение - СтароеЗначение;
		КонецЕсли;
		Если СтруктураОтчета.ИспользуютсяОбщиеВертикальныеИтогиНиз Тогда
			ЯчейкаОбщегоИтогаНиз = ТабличныйДокумент.Область(СтруктураОтчета.НомерСтрокиОбщихИтоговНиз, НомерКолонки);
			ЯчейкаОбщегоИтогаНиз.Значение = ЯчейкаОбщегоИтогаНиз.Значение + НовоеЗначение - СтароеЗначение;
		КонецЕсли;
		
		// обновление итогов вышестоящих группировок (снизу - вверх)
		
		ДопГоризонтальныеГруппировки = Новый Структура;
		СтартовыйИндекс = СтруктураОтчета.НомераСтрокВсехГоризонтальныхГруппировок.Найти(НомерСтроки) - 1;
		Для ОтрицательныйИндекс = -СтартовыйИндекс По 0 Цикл
			НомерСтрокиГруппировки = СтруктураОтчета.НомераСтрокВсехГоризонтальныхГруппировок[-ОтрицательныйИндекс];
			ДанныеДопГоризонтальнойГруппировки = СтруктураОтчета.СтрокиДопГоризонтальныхГруппировок[НомерСтрокиГруппировки];
			Если ДанныеДопГоризонтальнойГруппировки = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			Для Каждого ЭлементДанныхДопГоризонтальнойГруппировки Из ДанныеДопГоризонтальнойГруппировки Цикл
				ИмяГоризонтальнойГруппировки = ЭлементДанныхДопГоризонтальнойГруппировки.Ключ;
				Если СтруктураОтчета.ДопГоризонтальныеГруппировки[ИмяГоризонтальнойГруппировки] Тогда // если доп-группировка пересчитываемая
					Если НЕ ДопГоризонтальныеГруппировки.Свойство(ИмяГоризонтальнойГруппировки) Тогда
						ДопГоризонтальныеГруппировки.Вставить(ИмяГоризонтальнойГруппировки, НомерСтрокиГруппировки);
					КонецЕсли;
				КонецЕсли;
			КонецЦикла;
			
			Если ДопГоризонтальныеГруппировки.Количество() = СтруктураОтчета.ДопГоризонтальныеГруппировки.Количество() Тогда
				Прервать;
			КонецЕсли;
		КонецЦикла;
		Для Каждого ЭлементДопГоризонтальнойГруппировки Из ДопГоризонтальныеГруппировки Цикл
			ЯчейкаИтогаГруппировки = ТабличныйДокумент.Область(ЭлементДопГоризонтальнойГруппировки.Значение, НомерКолонки);
			ЯчейкаИтогаГруппировки.Значение = ЯчейкаИтогаГруппировки.Значение + НовоеЗначение - СтароеЗначение;
			ЯчейкаИтогаГруппировки.ЦветФона = СтруктураОтчета.ЦветРедактированныхЯчеек;
		КонецЦикла;
		
	КонецЕсли;
	
	// к сожалению, изменение дополнительных свойств компоновщика приводит к установке признака изменения варианта отчета и необходимо убрать последствия
	СброситьПризнакИзмененияВариантаОтчета(ФормаОтчета, Ложь);
	
КонецПроцедуры

Процедура ПриИзмененииСодержимогоОбласти(ФормаОтчета, ОповещениеРедактированияОтчета = Неопределено) Экспорт
	
	СтруктураОтчета = ФормаОтчета.Отчет.КомпоновщикНастроек.Настройки.ДополнительныеСвойства.СтруктураОтчета;
	
	Если НЕ СтруктураОтчета.Инициализирована Тогда
		ПоказатьПредупреждение(, "Обработка невозможна - структура отчета не была инициализирована корректно");	
		Возврат;
	КонецЕсли;
	
	Ячейка = ФормаОтчета.Элементы.Результат.ТекущаяОбласть;
	НомерТекущейКолонки = Ячейка.Лево;
	НомерТекущейСтроки = Ячейка.Верх;
	
	ДанныеСтроки = СтруктураОтчета.СтрокиГоризонтальнойКлючевойГруппировки.Получить(НомерТекущейСтроки);
	Если ДанныеСтроки <> Неопределено Тогда
		
		// определим имя текущей колонки и индекс вертикальной группировки
		ИмяРесурса = Неопределено;
		ИндексВертикальнойГруппировки = 0;
		Для Каждого ЭлементНомераКолонкиРесурса Из СтруктураОтчета.НомераКолонокРесурсов Цикл
			Для Каждого НомерКолонки Из ЭлементНомераКолонкиРесурса.Значение Цикл
				Если НомерКолонки = НомерТекущейКолонки Тогда
					ИмяРесурса = ЭлементНомераКолонкиРесурса.Ключ;
					ИндексВертикальнойГруппировки = ЭлементНомераКолонкиРесурса.Значение.Найти(НомерТекущейКолонки);
					Прервать;
				КонецЕсли;
			КонецЦикла;
			Если ИмяРесурса <> Неопределено Тогда
				Прервать;
			КонецЕсли;
		КонецЦикла;
		
		// если колонка редактируемая
		Если ИмяРесурса <> Неопределено И СтруктураОтчета.РедактируемыеРесурсы.Свойство(ИмяРесурса) Тогда
			
			СтароеЗначение = СтруктураОтчета.СтрокиГоризонтальнойКлючевойГруппировки[НомерТекущейСтроки][ИмяРесурса][ИндексВертикальнойГруппировки];
			НовоеЗначение = Ячейка.Значение;
			
			Если СтароеЗначение <> НовоеЗначение Тогда
			
				ПриИзмененииЗначенияРесурса(ФормаОтчета, НомерТекущейСтроки, ИмяРесурса, СтароеЗначение, Ячейка.Значение, ИндексВертикальнойГруппировки);
				ОповещениеРедактированияОтчета = ОповещениеРедактированияОтчета;
				Если ОповещениеРедактированияОтчета <> Неопределено Тогда
					ДопПараметры = Новый Структура;
					ДопПараметры.Вставить("СтруктураОтчета", СтруктураОтчета);
					ДопПараметры.Вставить("НомерСтроки", НомерТекущейСтроки);
					ДопПараметры.Вставить("ИмяРесурса", ИмяРесурса);
					ДопПараметры.Вставить("ИндексВертикальнойГруппировки", ИндексВертикальнойГруппировки);
					ДопПараметры.Вставить("СтароеЗначение", СтароеЗначение);
					ДопПараметры.Вставить("НовоеЗначение", НовоеЗначение);
					ВыполнитьОбработкуОповещения(ОповещениеРедактированияОтчета, ДопПараметры);
				КонецЕсли;
				
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

Процедура СброситьПризнакИзмененияВариантаОтчета(ФормаОтчета, СброситьПризнакИзмененияДанныхОтчета = Истина) Экспорт
	
	Если СброситьПризнакИзмененияДанныхОтчета Тогда
		ФормаОтчета.Отчет.КомпоновщикНастроек.Настройки.ДополнительныеСвойства.СтруктураОтчета.ДанныеИзменены = Ложь;
	КонецЕсли;
	ФормаОтчета.Элементы.Результат.ОтображениеСостояния.ДополнительныйРежимОтображения = ДополнительныйРежимОтображения.НеИспользовать;
	ФормаОтчета.Элементы.Результат.ОтображениеСостояния.Текст = "";
	ФормаОтчета.ВариантМодифицирован = Ложь;
	
КонецПроцедуры

Общий модуль "РедактируемыеОтчетыСервер":

// вызывается в ПриКомпоновкеРезультата
// возвращает значения ресурсов по строке группировки и преобразует ячейки отчета в редактируемые
Функция ПолучитьЗначенияРесурсовСтрокиОтчета(СтруктураОтчета, ТабличныйДокумент, НомерСтроки, ЭтоРедактируемаяГоризонтальнаяГруппировка = Ложь)
	
	СтруктураРесурсов = Новый Структура;
	
	НомераКолонокРесурсов = СтруктураОтчета.НомераКолонокРесурсов;
	ТипыРесурсов = СтруктураОтчета.ТипыРесурсов;
	
	Для Каждого ЭлементНомераКолонки Из НомераКолонокРесурсов Цикл
		
		ИмяРесурса = ЭлементНомераКолонки.Ключ;
		ИндексВертикальнойКлючевойГруппировки = 0;
		Для Каждого НомерКолонки Из НомераКолонокРесурсов[ИмяРесурса] Цикл
		
			Ячейка = ТабличныйДокумент.Область(НомерСтроки, НомерКолонки);
			ТипЯчейки = ТипыРесурсов[ЭлементНомераКолонки.Ключ];
			Значение = Ячейка.Текст;
			Если ТипЯчейки.СодержитТип(Тип("Число")) Тогда
				Значение = ?(ПустаяСтрока(Значение), 0, Число(Значение));
			ИначеЕсли ТипЯчейки.СодержитТип(Тип("Дата")) Тогда
				Если ПустаяСтрока(Значение) ИЛИ Найти(Значение, ".") = 0 ИЛИ СтрДлина(Значение) < 10 Тогда
					Значение = Дата(1,1,1);
				Иначе
					Значение = Дата(Сред(Значение,7,4)+Сред(Значение,4,2)+Сред(Значение,1,2));
				КонецЕсли;
			КонецЕсли;
			
			// преобразуем ячейку в содержащую значение
			Ячейка.СодержитЗначение = Истина;
			Ячейка.ТипЗначения = ТипЯчейки;
			Ячейка.Значение = Значение;
			Если ЭтоРедактируемаяГоризонтальнаяГруппировка И СтруктураОтчета.РедактируемыеРесурсы.Свойство(ИмяРесурса) Тогда
				Если СтруктураОтчета.МассивРедактируемыхЗначенийКлючевойВертикальнойГруппировки = Неопределено
				   ИЛИ СтруктураОтчета.МассивРедактируемыхЗначенийКлючевойВертикальнойГруппировки.Найти(СтруктураОтчета.ЗначенияВертикальнойКлючевойГруппировки[ИндексВертикальнойКлючевойГруппировки]) <> Неопределено Тогда
					Ячейка.Защита = Ложь;
				КонецЕсли;
			КонецЕсли;
			
			Если НЕ СтруктураРесурсов.Свойство(ЭлементНомераКолонки.Ключ) Тогда
				СтруктураРесурсов.Вставить(ЭлементНомераКолонки.Ключ, Новый Массив);
			КонецЕсли;
			СтруктураРесурсов[ЭлементНомераКолонки.Ключ].Добавить(Значение);
			ИндексВертикальнойКлючевойГруппировки = ИндексВертикальнойКлючевойГруппировки + 1;
			
		КонецЦикла;
		
	КонецЦикла;
	
	Возврат СтруктураРесурсов;
	
КонецФункции

// по переданному номеру строки ключевой горизонтальной группировки возвращает структуру, ключи которой - имена вышестоящих группировок, а значения - их значения
Функция ПолучитьЗначенияДопГоризонтальныхГруппировок(СтруктураОтчета, НомерСтрокиОтчета) Экспорт
	
	ЗначенияДопГоризонтальныхГруппировок = Новый Структура;
	
	СтартовыйИндекс = СтруктураОтчета.НомераСтрокВсехГоризонтальныхГруппировок.Найти(НомерСтрокиОтчета) - 1;
	Для ОтрицательныйИндекс = -СтартовыйИндекс По 0 Цикл
		НомерСтрокиГруппировки = СтруктураОтчета.НомераСтрокВсехГоризонтальныхГруппировок[-ОтрицательныйИндекс];
		ДанныеДопГоризонтальнойГруппировки = СтруктураОтчета.СтрокиДопГоризонтальныхГруппировок[НомерСтрокиГруппировки];
		Если ДанныеДопГоризонтальнойГруппировки = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		Для Каждого ЭлементДанныхДопГоризонтальнойГруппировки Из ДанныеДопГоризонтальнойГруппировки Цикл
			ИмяГоризонтальнойГруппировки = ЭлементДанныхДопГоризонтальнойГруппировки.Ключ;
			ЗначениеГоризонтальнойГруппировки = ЭлементДанныхДопГоризонтальнойГруппировки.Значение;
			Если НЕ ЗначенияДопГоризонтальныхГруппировок.Свойство(ИмяГоризонтальнойГруппировки) Тогда
				ЗначенияДопГоризонтальныхГруппировок.Вставить(ИмяГоризонтальнойГруппировки, ЗначениеГоризонтальнойГруппировки);
			КонецЕсли;
		КонецЦикла;
		
		Если ЗначенияДопГоризонтальныхГруппировок.Количество() = СтруктураОтчета.ДопГоризонтальныеГруппировки.Количество() Тогда
			Прервать;
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат ЗначенияДопГоризонтальныхГруппировок;
	
КонецФункции

// возвращает данные отчета в виде таблицы значений
Функция ПолучитьТаблицуРезультата(КомпоновщикНастроек) Экспорт
	
	СтруктураОтчета = КомпоновщикНастроек.Настройки.ДополнительныеСвойства.СтруктураОтчета;
	
	// создадим таблицу результата
	ТаблицаРезультата = Новый ТаблицаЗначений;
	ТаблицаРезультата.Колонки.Добавить(СтруктураОтчета.ИмяКлючевойГоризонтальнойГруппировки);
	Если ЗначениеЗаполнено(СтруктураОтчета.ИмяКлючевойВертикальнойГруппировки) Тогда
		ТаблицаРезультата.Колонки.Добавить(СтруктураОтчета.ИмяКлючевойВертикальнойГруппировки);
	КонецЕсли;
	Если СтруктураОтчета.ДопГоризонтальныеГруппировки <> Неопределено Тогда
		Для Каждого ЭлементГоризонтальнойДопГруппировки Из СтруктураОтчета.ДопГоризонтальныеГруппировки Цикл
			ТаблицаРезультата.Колонки.Добавить(ЭлементГоризонтальнойДопГруппировки.Ключ);
		КонецЦикла;
	КонецЕсли;
	Для Каждого ЭлементТипаРесурса Из СтруктураОтчета.ТипыРесурсов Цикл
		ТаблицаРезультата.Колонки.Добавить(ЭлементТипаРесурса.Ключ, ЭлементТипаРесурса.Значение);
	КонецЦикла;
	
	// заполним таблицу результата
	Для Каждого ЭлементГоризонтальнойКлючевойГруппировки Из СтруктураОтчета.СтрокиГоризонтальнойКлючевойГруппировки Цикл
		ДанныеГоризонтальнойКлючевойГруппировки = ЭлементГоризонтальнойКлючевойГруппировки.Значение;
		Если НЕ ЗначениеЗаполнено(СтруктураОтчета.ИмяКлючевойВертикальнойГруппировки) Тогда // нет вертикальных группировок (читаем одну комбинацию ресурсов)
			СтрокаРезультата = ТаблицаРезультата.Добавить();
			СтрокаРезультата[СтруктураОтчета.ИмяКлючевойГоризонтальнойГруппировки] = ДанныеГоризонтальнойКлючевойГруппировки[СтруктураОтчета.ИмяКлючевойГоризонтальнойГруппировки];
			Для Каждого ЭлементИмениРесурса Из СтруктураОтчета.ИменаРесурсов Цикл
				ИмяРесурса = ЭлементИмениРесурса.Ключ;
				СтрокаРезультата[ИмяРесурса] = ДанныеГоризонтальнойКлючевойГруппировки[ИмяРесурса][0]
			КонецЦикла;
			Для Каждого ЗначениеДопГоризонтальнойГруппировки Из ПолучитьЗначенияДопГоризонтальныхГруппировок(СтруктураОтчета, ЭлементГоризонтальнойКлючевойГруппировки.Ключ) Цикл
				СтрокаРезультата[ЗначениеДопГоризонтальнойГруппировки.Ключ] = ЗначениеДопГоризонтальнойГруппировки.Значение;
			КонецЦикла;
		Иначе // есть вертикальные группировки (читаем ресурсы по каждому значению вертикальной группировки)
			ИндексВертикальнойКлючевойГруппировки = 0;
			Для Каждого ЗначениеВертикальнойКлючевойГруппировки Из СтруктураОтчета.ЗначенияВертикальнойКлючевойГруппировки Цикл
				СтрокаРезультата = ТаблицаРезультата.Добавить();
				СтрокаРезультата[СтруктураОтчета.ИмяКлючевойГоризонтальнойГруппировки] = ДанныеГоризонтальнойКлючевойГруппировки[СтруктураОтчета.ИмяКлючевойГоризонтальнойГруппировки];
				СтрокаРезультата[СтруктураОтчета.ИмяКлючевойВертикальнойГруппировки] = ЗначениеВертикальнойКлючевойГруппировки;
				Для Каждого ЭлементИмениРесурса Из СтруктураОтчета.ИменаРесурсов Цикл
					ИмяРесурса = ЭлементИмениРесурса.Ключ;
					СтрокаРезультата[ИмяРесурса] = ДанныеГоризонтальнойКлючевойГруппировки[ИмяРесурса][ИндексВертикальнойКлючевойГруппировки]
				КонецЦикла;
				Для Каждого ЗначениеДопГоризонтальнойГруппировки Из ПолучитьЗначенияДопГоризонтальныхГруппировок(СтруктураОтчета, ЭлементГоризонтальнойКлючевойГруппировки.Ключ) Цикл
					СтрокаРезультата[ЗначениеДопГоризонтальнойГруппировки.Ключ] = ЗначениеДопГоризонтальнойГруппировки.Значение;
				КонецЦикла;
				ИндексВертикальнойКлючевойГруппировки = ИндексВертикальнойКлючевойГруппировки + 1;
			КонецЦикла;
		КонецЕсли;
	КонецЦикла;
	
	Возврат ТаблицаРезультата;
	
КонецФункции

Процедура ПриКомпоновкеРезультата(КомпоновщикНастроек, ТабличныйДокумент, ДанныеРасшифровкиОтчета, СхемаКомпоновкиДанных, СтандартнаяОбработка) Экспорт
	
	// выполним компоновку, если отчет выполняет стандартную компоновку
	Если СтандартнаяОбработка Тогда
		СтандартнаяОбработка = Ложь;
		КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
		МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки(), ДанныеРасшифровкиОтчета);
		ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
		ПроцессорКомпоновки.Инициализировать(МакетКомпоновки,,ДанныеРасшифровкиОтчета);
		ТабличныйДокумент.Очистить();
		ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
		ПроцессорВывода.УстановитьДокумент(ТабличныйДокумент);
		ПроцессорВывода.Вывести(ПроцессорКомпоновки);
	КонецЕсли;
	
	СтруктураОтчета = КомпоновщикНастроек.Настройки.ДополнительныеСвойства.СтруктураОтчета;
	
	// соответствие ресурсов номерам колонок
	НомераКолонокРесурсов = Новый Структура;
	Для Каждого ЭлементИмениКолонки Из СтруктураОтчета.ИменаРесурсов Цикл
		НомераКолонокРесурсов.Вставить(ЭлементИмениКолонки.Ключ, Неопределено);
	КонецЦикла;
	
	// определим высоту заголовка (до начала области расшифровок)
	НомерПервойСтрокиРасшифровки = Неопределено;
	Для НомерСтроки = 1 По ТабличныйДокумент.ВысотаТаблицы Цикл
		Ячейка = ТабличныйДокумент.Область(НомерСтроки, 1);
		Если Ячейка.Расшифровка <> Неопределено Тогда
			НомерПервойСтрокиРасшифровки = НомерСтроки;
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	Если НомерПервойСтрокиРасшифровки = Неопределено Тогда
		СтруктураОтчета.ТекстОшибкиИнициализации = "Ошибка инициализации структуры отчета";	
		Возврат;
	КонецЕсли;
		
	СтруктураОтчета.Вставить("НомерПервойСтрокиРасшифровки", НомерПервойСтрокиРасшифровки);
	
	// определим номера колонок по их заголовкам или расшифровке
	Для НомерКолонки = 1 По ТабличныйДокумент.ШиринаТаблицы Цикл
		Для НомерСтроки = 1 По НомерПервойСтрокиРасшифровки + 5 Цикл
			Ячейка = ТабличныйДокумент.Область(НомерСтроки, НомерКолонки);
			ПоляРасшифровки = Новый Массив;
			Если Ячейка.Расшифровка <> Неопределено Тогда
				ПоляРасшифровки = ДанныеРасшифровкиОтчета.Элементы[Ячейка.Расшифровка].ПолучитьПоля();
			КонецЕсли;
			Для Каждого ЭлементИмениКолонки Из СтруктураОтчета.ИменаРесурсов Цикл
				// поиск колонок ресурсов по имени колонке в тексте ячейки либо по наличию расшифровки
				Если Ячейка.Текст = ЭлементИмениКолонки.Значение ИЛИ ПоляРасшифровки.Найти(ЭлементИмениКолонки.Значение) <> Неопределено Тогда
					Если НомераКолонокРесурсов[ЭлементИмениКолонки.Ключ] = Неопределено Тогда
						НомераКолонокРесурсов[ЭлементИмениКолонки.Ключ] = Новый Массив;
					КонецЕсли;
					Если НомераКолонокРесурсов[ЭлементИмениКолонки.Ключ].Найти(НомерКолонки) = Неопределено Тогда
						НомераКолонокРесурсов[ЭлементИмениКолонки.Ключ].Добавить(НомерКолонки);
					КонецЕсли;
				КонецЕсли;
			КонецЦикла;
		КонецЦикла;
	КонецЦикла;
	
	// проверим все ли номера ресурсов определены
	Для Каждого ЭлементНомераКолонки Из НомераКолонокРесурсов Цикл
		Если НЕ ЗначениеЗаполнено(ЭлементНомераКолонки.Значение) Тогда
			СтруктураОтчета.ТекстОшибкиИнициализации = "Ошибка анализа структуры отчета - не найден ресурс с названием """ + СтруктураОтчета.ИменаРесурсов[ЭлементНомераКолонки.Ключ];
			Возврат;
		КонецЕсли;
	КонецЦикла;
	
	СтруктураОтчета.Вставить("НомераКолонокРесурсов", НомераКолонокРесурсов);
	СтруктураОтчета.Вставить("НомерСтрокиОбщихИтоговВерх", НомерПервойСтрокиРасшифровки - 1);
	СтруктураОтчета.Вставить("НомерСтрокиОбщихИтоговНиз", ТабличныйДокумент.ВысотаТаблицы);
	СтруктураОтчета.Вставить("СтрокиГоризонтальнойКлючевойГруппировки", Новый Соответствие);
	СтруктураОтчета.Вставить("СтрокиДопГоризонтальныхГруппировок", Новый Соответствие);
	СтруктураОтчета.Вставить("НомераСтрокВсехГоризонтальныхГруппировок", Новый Массив);
	СтруктураОтчета.Вставить("ЗначенияВертикальнойКлючевойГруппировки", Неопределено);
	
	Для НомерСтроки = СтруктураОтчета.НомерПервойСтрокиРасшифровки По ТабличныйДокумент.ВысотаТаблицы - 1 Цикл
		
		// определим строки, значения и значения ресурсов по горизонтальной ключевой группировке
		
		ЯчейкаПервойКолонки = ТабличныйДокумент.Область(НомерСтроки, 1);
		Если ЯчейкаПервойКолонки.Расшифровка = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		ЭлементРасшифровки = ДанныеРасшифровкиОтчета.Элементы[ЯчейкаПервойКолонки.Расшифровка];
		ТекущаяГруппировка = ЭлементРасшифровки.ПолучитьРодителей()[0].ПолучитьПоля()[0];
		
		Если ТекущаяГруппировка.Поле = СтруктураОтчета.ИмяКлючевойГоризонтальнойГруппировки Тогда
			
			// определим значения вертикальной ключевой группировки (однократно - по первой строке горизонтальной ключевой группировки)
			Если СтруктураОтчета.ЗначенияВертикальнойКлючевойГруппировки = Неопределено И ЗначениеЗаполнено(СтруктураОтчета.ИмяКлючевойВертикальнойГруппировки) Тогда
				СтруктураОтчета.ЗначенияВертикальнойКлючевойГруппировки = Новый Массив;
				НомераКолонокЛюбогоРесурса = Неопределено;
				Для Каждого ЭлементНомераКолонки Из СтруктураОтчета.НомераКолонокРесурсов Цикл
					НомераКолонокЛюбогоРесурса = ЭлементНомераКолонки.Значение;
					Прервать;
				КонецЦикла;
				Если НомераКолонокЛюбогоРесурса <> Неопределено Тогда
					Для Каждого НомерКолонки Из НомераКолонокЛюбогоРесурса Цикл
						ЯчейкаКолонкиРесурса = ТабличныйДокумент.Область(НомерСтроки, НомерКолонки);
						Если ЯчейкаКолонкиРесурса.Расшифровка = Неопределено Тогда
							Продолжить;
						КонецЕсли;
						ЭлементРасшифровки = ДанныеРасшифровкиОтчета.Элементы[ЯчейкаКолонкиРесурса.Расшифровка];
						Для Каждого РодительЭлемента Из ЭлементРасшифровки.ПолучитьРодителей() Цикл
							Для Каждого ПолеРодителя Из РодительЭлемента.ПолучитьПоля() Цикл
								Если ПолеРодителя.Поле = СтруктураОтчета.ИмяКлючевойВертикальнойГруппировки Тогда
									СтруктураОтчета.ЗначенияВертикальнойКлючевойГруппировки.Добавить(ПолеРодителя.Значение);
								КонецЕсли;
							КонецЦикла;
						КонецЦикла;
					КонецЦикла;
				КонецЕсли;
			КонецЕсли;
	
			// получим данные по ключевой горизонтальной группировке
			ЗначениеКлючевойГоризонтальнойГруппировки = ТекущаяГруппировка.Значение;
			ЭтоРедактируемаяГоризонтальнаяГруппировка = СтруктураОтчета.МассивРедактируемыхЗначенийКлючевойГоризонтальнойГруппировки = Неопределено ИЛИ СтруктураОтчета.МассивРедактируемыхЗначенийКлючевойГоризонтальнойГруппировки.Найти(ЗначениеКлючевойГоризонтальнойГруппировки) <> Неопределено;
			РесурсыСтрокиОтчета = ПолучитьЗначенияРесурсовСтрокиОтчета(СтруктураОтчета, ТабличныйДокумент, НомерСтроки, ЭтоРедактируемаяГоризонтальнаяГруппировка);
			РесурсыСтрокиОтчета.Вставить(СтруктураОтчета.ИмяКлючевойГоризонтальнойГруппировки, ЗначениеКлючевойГоризонтальнойГруппировки);
			СтруктураОтчета.СтрокиГоризонтальнойКлючевойГруппировки.Вставить(НомерСтроки, РесурсыСтрокиОтчета);
			СтруктураОтчета.НомераСтрокВсехГоризонтальныхГруппировок.Добавить(НомерСтроки);
			
		ИначеЕсли СтруктураОтчета.ДопГоризонтальныеГруппировки <> Неопределено И СтруктураОтчета.ДопГоризонтальныеГруппировки.Свойство(ТекущаяГруппировка.Поле) Тогда
			
			СтруктураОтчета.СтрокиДопГоризонтальныхГруппировок.Вставить(НомерСтроки, Новый Структура(ТекущаяГруппировка.Поле, ТекущаяГруппировка.Значение));
			СтруктураОтчета.НомераСтрокВсехГоризонтальныхГруппировок.Добавить(НомерСтроки);
			
			Если СтруктураОтчета.ДопГоризонтальныеГруппировки[ТекущаяГруппировка.Поле] Тогда // если необходим пересчет
				// вызов нижестоящего метода требуется исключительно для преобразования ячеек ресурсов с итогами вышестоящих группировок в содержащие значение
				ПолучитьЗначенияРесурсовСтрокиОтчета(СтруктураОтчета, ТабличныйДокумент, НомерСтроки);
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЦикла;
	
	// преобразуем в значения ресурсы строк с вертикальными итогами
	Если СтруктураОтчета.ИспользуютсяОбщиеВертикальныеИтогиВерх Тогда
		ПолучитьЗначенияРесурсовСтрокиОтчета(СтруктураОтчета, ТабличныйДокумент, СтруктураОтчета.НомерСтрокиОбщихИтоговВерх);
	КонецЕсли;
	Если СтруктураОтчета.ИспользуютсяОбщиеВертикальныеИтогиНиз Тогда
		ПолучитьЗначенияРесурсовСтрокиОтчета(СтруктураОтчета, ТабличныйДокумент, СтруктураОтчета.НомерСтрокиОбщихИтоговНиз);
	КонецЕсли;
	
	СтруктураОтчета.Инициализирована = Истина;
	
КонецПроцедуры

// выполняет инициализацию структуры отчета, сохраняет ее в параметрах компоновщика настроек и возвращает ссылку на нее для дополнительных донастроек редактируемого отчета
Функция ИнициализироватьСтруктуруОтчета(КомпоновщикНастроек, ИмяКлючевойГоризонтальнойГруппировки, ИмяКлючевойВертикальнойГруппировки = "") Экспорт
	
	СтруктураОтчета = Новый Структура();
	СтруктураОтчета.Вставить("Инициализирована", Ложь); 						// была ли выполнена инициализация структуры отчета после компоновки
	СтруктураОтчета.Вставить("ДанныеИзменены", Ложь); 							// были ли изменены данные пользователем
	СтруктураОтчета.Вставить("ТекстОшибкиИнициализации", ""); 					// будет содержать описание ошибки инициализации, если произошла ошибка инициализации
	СтруктураОтчета.Вставить("ИмяКлючевойГоризонтальнойГруппировки", ИмяКлючевойГоризонтальнойГруппировки);
	СтруктураОтчета.Вставить("ИмяКлючевойВертикальнойГруппировки", ИмяКлючевойВертикальнойГруппировки);
	СтруктураОтчета.Вставить("ДопГоризонтальныеГруппировки", Неопределено); 	// сюда при необходимоти необходимо передать структуру, ключи которой содержат имена доп-группировок, а значения - необходимость пересчета итогов по ним
	СтруктураОтчета.Вставить("ИспользуютсяОбщиеВертикальныеИтогиВерх", Ложь); 	// признак использования верхних вертикальных итогов (изменить при необходимости)
	СтруктураОтчета.Вставить("ИспользуютсяОбщиеВертикальныеИтогиНиз", Истина);	// признак использования нижних вертикальных итогов (изменить при необходимости)
	СтруктураОтчета.Вставить("ИменаРесурсов", Новый Структура()); 				// служебное (заполняется при вызове ДобавитьРесурсВСтруктуруОтчета)
	СтруктураОтчета.Вставить("ТипыРесурсов", Новый Структура()); 				// служебное (заполняется при вызове ДобавитьРесурсВСтруктуруОтчета)
	СтруктураОтчета.Вставить("ФорматыРесурсов", Новый Структура()); 			// служебное (заполняется при вызове ДобавитьРесурсВСтруктуруОтчета)
	СтруктураОтчета.Вставить("РесурсыСПересчетомИтогов", Новый Структура()); 	// служебное (заполняется при вызове ДобавитьРесурсВСтруктуруОтчета)
	СтруктураОтчета.Вставить("РедактируемыеРесурсы", Новый Структура()); 		// служебное (заполняется при вызове ДобавитьРесурсВСтруктуруОтчета)
	СтруктураОтчета.Вставить("МассивРедактируемыхЗначенийКлючевойГоризонтальнойГруппировки", Неопределено); // необходим в случаях, когда не по всем значениям ключевой горизонтальной группировки необходимо разрешить редактировать данные
	СтруктураОтчета.Вставить("МассивРедактируемыхЗначенийКлючевойВертикальнойГруппировки", Неопределено); 	// необходим в случаях, когда не по всем значениям ключевой вертикальной группировки необходимо разрешить редактировать данные
	СтруктураОтчета.Вставить("ЦветРедактированныхЯчеек", WebЦвета.СветлоЖелтый);// цвет отображения отредактированных ячеек (изменить при необходимости)
	
	КомпоновщикНастроек.Настройки.ДополнительныеСвойства.Вставить("СтруктураОтчета", СтруктураОтчета);
	
	Возврат СтруктураОтчета;
	
КонецФункции

// добавляет в структуру отчета информацию о новом ресурсе
Процедура ДобавитьРесурсВСтруктуруОтчета(КомпоновщикНастроек, Имя, Тип, Формат, Представление, Пересчитывается = Ложь, Редактируется = Ложь) Экспорт
	
	СтруктураОтчета = КомпоновщикНастроек.Настройки.ДополнительныеСвойства.СтруктураОтчета;
	
	СтруктураОтчета.ИменаРесурсов.Вставить(Имя, Представление);
	СтруктураОтчета.ТипыРесурсов.Вставить(Имя, Тип);
	СтруктураОтчета.ФорматыРесурсов.Вставить(Имя, Формат);
	
	Если Пересчитывается Тогда
		СтруктураОтчета.РесурсыСПересчетомИтогов.Вставить(Имя);
	КонецЕсли;
	
	Если Редактируется Тогда
		СтруктураОтчета.РедактируемыеРесурсы.Вставить(Имя);
	КонецЕсли;
	
КонецПроцедуры

 

отчет СКД редактируемый Excel формулы пересчет

См. также

Богатый редактор картинок, хранимых в базе, с возможностью РИСОВАНИЯ. Редактор внешних файлов картинок. Объект, расширяющий возможности работы с картинками из встроенного языка (Три в одном) + Обработка «Стандартизация картинок»

Работа с интерфейсом Рабочее место Платформа 1С v8.3 Управляемые формы Конфигурации 1cv8 Платные (руб)

Обработка предназначена для редактирования картинок в режиме «Предприятие», с возможностью РИСОВАТЬ на них. Поддерживается работа как в обычных формах (толстый клиент) так и на управляемых формах (тонкий клиент). Обработка позволяет редактировать как картинки, хранимые в базе, так и графические файлы с диска на файловой системе. Помимо базовых функций (изменение размеров, преобразование формата, обрезание картинки, повороты и т.п.) – редактор имеет богатый набор инструментов для рисования. Доступна функция вставки изображения из буфера обмена. Также обработка может быть использована из встроенного языка как объект для редактирования картинок. Объект может быть использован: на стороне клиента, на стороне сервера, из внешнего соединения. Данная обработка будет особенно полезна тем, кто вносит картинки в базу (изображения номенклатуры, фотографии физических лиц и т.п.). Функционал реализуется с использованием JavaScript и бесплатного ПО ImageMagick (без использования внешних компонент).

6000 руб.

16.01.2015    61973    43    59    

81

[Расширения] Динамическое управление видимостью и доступностью элементов форм (УФ) (8.3.6+)

Работа с интерфейсом Платформа 1С v8.3 Управляемые формы Конфигурации 1cv8 Платные (руб)

Механизм «Динамическое управление доступом к элементам форм объектов 1С8» предназначен для обеспечения возможности оперативного управления видимостью и доступностью элементов форм документов и справочников продуктов фирмы «1С» «1С:Предприятие 8». Решение универсальное, встраивается в любую конфигурацию с минимальными доработками, что позволяет без проблем обновлять типовые решения.

5000 руб.

14.01.2016    54600    16    21    

42

Управление дашбордами

Работа с интерфейсом Платформа 1С v8.3 Конфигурации 1cv8 Платные (руб)

Обработка предназначена для создания и управления дашбордами.

2400 руб.

29.06.2020    16849    21    4    

35

Новогоднее оформление для 1С

Работа с интерфейсом Платформа 1С v8.3 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Зарплата и Управление Персоналом 3.x 1С:Управление нашей фирмой 3.0 Бесплатно (free)

Добавьте новогоднего настроения! Расширение создает декорацию в виде гирлянды на некоторых формах объектов.

27.12.2023    11037    757    elcoan    45    

106

Конструктор HTML, CSS и javascript

Инструментарий разработчика Работа с интерфейсом Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Подходит для создания web-страниц для замены управляемых форм 1С, красивых отчетов, интерфейса мобильного приложения на платформе 1С и для простых страниц веб-сайтов.

2 стартмани

10.04.2023    9809    153    acces969    31    

119

Модель состояния для MVC

Работа с интерфейсом Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

"MVC плохо применима в 1С" - познакомьтесь с моделью состояния и, возможно, ваше мнение поменяется! Представленное решение является эволюционным развитием идеи реализации MVC для 1С. В новой версии добавлены DSL для описания модели состояния, а также параметризация свойств параметров и элементов формы.

1 стартмани

05.07.2022    3867    kalyaka    4    

29

Табло очереди заказов на экран телевизора

WEB-интеграция Работа с интерфейсом Платформа 1С v8.3 1С:Розница 2 Платные (руб)

Связка из веб-приложения и расширения для 1С: Розница 2.3.

3600 руб.

29.04.2022    12228    1    5    

10

Условное оформление элементов форм в пользовательском режиме 1С (управление видимостью и доступностью элементов форм)

Работа с интерфейсом Платформа 1С v8.3 Платные (руб)

Подсистема условного оформления элементов форм (далее подсистема) предназначена для настройки оформления элементов форм (видимость, доступность, цвет фона, цвет текста и прочее) в пользовательском режиме 1С. Также подсистему возможно использовать для ограничения доступа к реквизитам формы для определенных пользователей (или групп пользователей).

6000 руб.

18.01.2022    8901    1    2    

6
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. leobrn 617 27.01.20 12:40 Сейчас в теме
за основу брали данную работу https://infostart.ru/public/158630/?
+
2. herfis 498 27.01.20 14:23 Сейчас в теме
(1) Не, "с нуля" велосипедил. Чорд и ведь искал похожее, а не нашел :(
Глянул презентацию. Там несколько другой подход. Из того, что сразу заметил:
1) сразу после компоновки автор "переделывает" ячейки отчета на содержащие значения, что позволяет в итоге нативно редактировать данные "по месту" (у меня через диалог сейчас по дабл-клику). Хм... Об этом я как-то не подумал :) Интересная идея, возможно возьму на вооружение.
2) проблему получения значений ресурсов (я их сейчас из текста ячеек беру) решает через макеты СКД. Это мне не нравится. Способ надежный, но не хочется трогать схему.
3) изменения автор не буферизирует, а сразу отражает в регистрах при редактировании каждой ячейки. У меня в каждый момент времени в памяти хранится актуальный "образ" всех данных отчета. Все сделанные изменения можно по итогу либо записать, либо отменить.
ЗЫ. Интересно будет глянуть, как реализован пересчет вышестоящих группировок. Возможно позже скачаю и гляну.
leobrn; +1
15. herfis 498 06.02.20 18:33 Сейчас в теме
Подумал-подумал, и решил таки переделать.
1) хочу перенести инициализацию структуры отчета в ПриКомпоновке (это позволит заметно упростить структуру подсистемы плюс на клиенте не будет тратится доп-время на запуск). Внедрение подсистемы также упростится.
2) редактирование ресурсов будет не в диалоге, а непосредственно в ячейке, эту идею я подсмотрел в (1)
Остальные принципы останутся теми же. Сейчас новая версия проходит обкатку. Вероятно, попутно добавится и кое-какая функциональность.
+
3. Dzenn 874 27.01.20 15:29 Сейчас в теме
"Хороший способ. Использовать я его, конечно же, не буду." © не мой ;-)
maksa2005; zqzq; +2
5. herfis 498 27.01.20 16:13 Сейчас в теме
(3) "Не хочется трогать схему" - подразумевалось что не хочется, чтобы ее пришлось трогать разработчику, внедряющему функциональность. Ведь это разработчику придется создавать и настраивать макеты СКД для ресурсов отчета, чтобы их можно было человечески прочитать программно. Читать из текста ячеек мне кажется меньшим из зол.
+
4. herfis 498 27.01.20 15:47 Сейчас в теме
Уже почти было собрался переписать так, чтобы анализ структуры отчета делался на сервере при компоновке.
Это дало бы сразу много плюшек:
1) не надо перехватывать компоновку на клиенте
2) не надо перехватывать ПриОткрытии()
3) можно отказаться от клиентской переменной для хранения структуры отчета
4) анализ данных отчета делался бы быстрее и не приводил бы к задержкам на клиенте
5) несколько процедур можно было бы объединить в одну
Правда, все это ценой засовывания структуры отчета в клиент-серверный контекст формы, но это вроде не страшно. Не так часто в отчете он дергается.
Остановила одна-единственная вещь. Компоновку на клиенте все равно перехватывать нужно, хотя бы просто для того, чтобы сообщить о наличии не записанных изменений :( А раз так, то внедряться еще и в событие компоновки на сервере выглядит несколько излишним...
+
6. МимохожийОднако 141 02.02.20 07:29 Сейчас в теме
Работа с дополнительными реквизитами справочника возможна? Есть пример?
+
7. herfis 498 03.02.20 10:20 Сейчас в теме
(6) Что имеется в виду? Какая именно работа? Что наваяете в запросе СКД, то и будет. Включая работу с доп-реквизитами справочника. К сабжевому механизму это никакого отношения не имеет.
+
8. МимохожийОднако 141 03.02.20 13:59 Сейчас в теме
Например, завели в справочник Номенклатура дополнительные реквизиты в режиме Предприятие. Они будут отображаться для редактирования?
+
9. herfis 498 03.02.20 15:14 Сейчас в теме
(8) Инструменту все равно, какой ресурс СКД к чему относится и каким образом этот ресурс был вычислен. Вычисляемое это поле или берется из доп-реквизитов какого-то справочника. Берется ЛЮБОЙ отчет СКД и настраивается какие его РЕСУРСЫ будут редактироваться в разрезе ключевых группировок. Как потом обрабатывать полученные после редактирования результаты - тоже дело программиста.
По вашим словам, вы это видите как какой-то универсальный инструмент редактирования каких-то объектов. Нет. Это про другое.
+
10. МимохожийОднако 141 03.02.20 18:53 Сейчас в теме
Сталкивался с ситуацией, когда в номенклатуру добавляли доп.реквизиты, а заполнять их неудобно из-за больших объемов. Если бы была возможность заполнить таблицу на форме и подредактированную загрузить в базу с изменёнными данными, то пользователи были бы счастливы. На худой конец, сохранять табличный документ в Еxcel, править и... загружать обратно. ))
+
11. herfis 498 03.02.20 19:02 Сейчас в теме
(10) Эту задачу можно решить с помощью сабжевого инструмента. Но "из коробки" он ее не решает.
Программист может написать отчет СКД, который выведет в качестве ресурсов значения нужных доп-реквизитов.
Потом можно на этот отчет "натравить" сабжевую технологию, сделав эти ресурсы "редактируемыми".
После этого программист должен будет написать код, который запишет отредактированные значения обратно в справочник.
Только это выглядит как разовая задача. Слабо себе могу представить такой вариант, когда пользователю на постоянной основе нужно открывать список и массово в него фигачить изменения. Сразу возникает вопрос - откуда он берет эту информацию? Может, можно автоматизировать загрузку из этого источника?
+
12. МимохожийОднако 141 03.02.20 19:14 Сейчас в теме
(11) Я назвал реальный пример. Есть база Розницы 2. Решили открыть сайт с товаром. Для отдельных видов товаров добавили наборы доп.реквизитов, которые потом будут выгружаться на сайт. Оператор должен заполнить эти реквизиты. Колотит и плачет, колотит и плачет...
+
13. herfis 498 04.02.20 10:17 Сейчас в теме
(12) Не вижу никакого смысла заморачиваться с редактированием этих реквизитов через отчет. Я бы реализовал через таблицу на форме.
+
14. pm74 199 06.02.20 08:31 Сейчас в теме
(0) знакомая тема : "сделайте нам тут как в Exel"
тоже монстрил что-то подобное
https://github.com/pm74/_37583/tree/master/epf
+
16. herfis 498 02.03.20 10:15 Сейчас в теме
Переделал, как и собирался. Из наиболее значительных изменений:
- анализ данных отчета перенесен с клиента на сервер (при компоновке), что в том числе позволило упростить использование
- редактирование данных теперь осуществляется непосредственно в ячейках отчета
- результаты теперь можно хранить и получать в разрезе вышестоящих группировок
- ну и ряд оптимизаций, улучшений и упрощений
Встречайте :)
+
Оставьте свое сообщение