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

Публикация № 1184138

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

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

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

Решаемая проблема
Периодически у меня возникала следующая задача: необходимо было разработать некий расчетный инструмент или инструмент планирования, который рассчитывает на основании каких-то данных некие показатели, а пользователь должен иметь возможность при необходимости их скорректировать и зафиксировать в системе итоговый результат.
И в этот момент возникает проблема, поскольку этот инструмент с одной стороны является во многом аналитическим и должен предоставлять пользователю информацию для принятия решений в максимально удобной форме, а с другой стороны - должен позволять в удобном виде редактировать информацию и записывать ее в систему.
Для первого в 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 (ну, почти):

.cf 22,72Kb
18
.cf 22,72Kb 18 Скачать

Специальные предложения

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

См. также

Альтернативный способ добавления элементов и реквизитов на формы Промо

Работа с интерфейсом v8 ERP2 УТ11 Россия Абонемент ($m)

Предлагаю альтернативный вариант добавления динамически создаваемых элементов и реквизитов на форму.

1 стартмани

09.09.2019    15139    29    bmk74    6    

Интерактивная справка по объектам 1С (подключаемое расширение)

Практика программирования Работа с интерфейсом v8 ERP2 Абонемент ($m)

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

3 стартмани

29.09.2020    11873    69    sapervodichka    43    

Визуальный html WYSIWYG редактор без сторонних библиотек на управляемых формах

Прочие инструменты разработчика Работа с интерфейсом v8 v8::УФ 1cv8.cf Абонемент ($m)

Простой и удобный html редактор без сторонних библиотек.

1 стартмани

31.08.2020    6345    10    ivanov660    12    

Индикация прогресса выполнения фонового задания на управляемой форме внешней обработки

БСП (Библиотека стандартных подсистем) Работа с интерфейсом v8 v8::УФ 1cv8.cf Абонемент ($m)

Внешняя обработка с фоновым выполнением и индикацией процесса для любой конфигурации на основе БСП >= 2.3 без изменения конфигурации и встраивания обработки в "Дополнительные отчеты и обработки".

1 стартмани

27.12.2019    15875    29    1sig    14    

Расширенная настройка динамического списка УФ Промо

Работа с интерфейсом v8 v8::УФ 1cv8.cf Абонемент ($m)

Открывая управляемую форму выбора и не увидев там видимых в форме списка элементов, часто хочется узнать причину их отсутствия там, т. е. какой наложен отбор. Но стандартная настройка списка управляемой формы показывает только пользовательские настройки, скрывая от пользователя фиксированный отбор. Предлагаю вам расширение конфигурации с расширенной настройкой динамического списка, отображающей пользователю кроме пользовательских настроек еще фиксированные.

1 стартмани

31.05.2017    36675    161    tormozit    25    

Декомпиляция условного оформления

Работа с интерфейсом v8 1cv8.cf Абонемент ($m)

Обработка автоматически генерирует полный код создания условного оформления формы любой сложности. Достаточно настроить для формы в конфигураторе условное оформление, а затем выбрать данную форму в обработке. В результате будет сгенерирован программный код создания условного оформления.

2 стартмани

23.12.2019    9994    46    XilDen    7    

Многоуровневые списки выбора с оформлением элементов

Практика программирования Работа с интерфейсом v8 v8::УФ 1cv8.cf Абонемент ($m)

Данная статья - попытка решить один маленький кусочек большой проблемы платформы 1С, а именно - бедные и невыразительные пользовательские интерфейсы. Поскольку 1С в режиме управляемого приложения позволяет задействовать веб-клиент, то хочется реализовывать интерфейсы как у взрослых веб-приложений - красивые, дружелюбные для пользователя и, желательно, с положительным UX. Возможно, кто-то со мной не согласится и скажет, что учетные системы должны быть строгие и линейные. Но мы все знаем, что 1С - это уже не только про бухгалтерию. Небольшое отступление для разработчиков, работающих с типовыми конфигурациями. Я не знаю, использует ли фирма 1С что-то похожее в своих разработках. Если да, то данная статья навряд ли будет вам полезна.

1 стартмани

17.12.2019    11021    2    azhilichev    5    

Удобный выбор из таблицы/дерева в УФ

Практика программирования Работа с интерфейсом Разработка v8 v8::УФ 1cv8.cf Абонемент ($m)

Выбор из таблицы значений или дерева значений в выпадающем списке рядом с полем ввода - УФ, быстро и просто!

1 стартмани

12.08.2019    16443    8    Yashazz    18    

[Механизм интерфейса] Свой флажок (чекбокс)

Работа с интерфейсом v8 1cv8.cf Абонемент ($m)

Создадим свой флажок для интерфейса, используем простой универсальный алгоритм.

1 стартмани

09.08.2019    19657    20    rpgshnik    43    

Отбор на управляемой форме из списка значений

Практика программирования Работа с интерфейсом Разработка v8 v8::УФ 1cv8.cf Абонемент ($m)

Пример простого удобного отбора любых данных ссылочного типа на управляемой форме. Работа обработки проверена на релизе: 1С:Предприятие 8.3.13.1513.

1 стартмани

09.08.2019    26602    27    nagaitseff    6    

Обработка-редактор HTML

Работа с интерфейсом v8 v8::УФ 1cv8.cf Абонемент ($m)

Редактор HTML для управляемого интерфейса 8.3.

1 стартмани

10.06.2019    11193    83    ValeriVP    11    

Открывашка ячеек таблиц Промо

Работа с интерфейсом v8 1cv8.cf Абонемент ($m)

Глобальное сочетание клавиш для открытия объекта по ссылке из текущей ячейки любой таблицы в большинстве управляемых форм

1 стартмани

27.10.2018    20298    12    tormozit    31    

Виртуальная (экранная) клавиатура для управляемых форм

Инструментарий разработчика Работа с интерфейсом v8 v8::УФ 1cv8.cf Абонемент ($m)

Предлагаю свой вариант виртуальной клавиатуры для использования в разработках, предполагающих использование сенсорного ввода.

1 стартмани

14.12.2018    15175    72    asdfgcom    16    

Рисуем и распознаем нарисованное при помощи нейросети

Практика программирования Работа с интерфейсом v8 v8::УФ 1cv8.cf Абонемент ($m)

Используем нейронную сеть для распознавания нарисованных объектов.

1 стартмани

03.10.2018    16899    45    DO_WHILE_LOOP    28    

Рисуем диаграммы в metadata.js

Инструментарий разработчика Работа с интерфейсом v8 v8::СКД 1cv8.cf Абонемент ($m)

Не одной же литературой заниматься?

1 стартмани

20.09.2018    19977    4    1c-intelligence    77    

Лучший подарок для бухгалтера - счёты 8.2 (со звуком) Промо

Работа с интерфейсом v8 1cv8.cf Россия Абонемент ($m)

(Толстый клиент) Подарите бухгалтеру счеты, и он(а) Вас никогда не забудет.

1 стартмани

13.05.2011    43131    922    Tatitutu    45    

Визуализация событий на временной шкале средствами "Поле HTML документа"

Работа с интерфейсом v8 1cv8.cf Абонемент ($m)

Интересный способ наглядно отобразить события на временной шкале. Например, может быть применен для красивого вывода документов по клиенту. Тестировалось на платформе 8.3.12.1469

1 стартмани

31.07.2018    26973    145    Plotks2017    27    

Продвинутое рисование в табличном документе (стрелок и не только)

Практика программирования Работа с интерфейсом v8 Абонемент ($m)

Вспоминаем геометрию и основы компьютерной графики. Матрицы и аффинные преобразования на плоскости.

1 стартмани

24.07.2018    18801    20    WalterMort    30    

Работа с данными выбора

Практика программирования Работа с интерфейсом v8 Россия Абонемент ($m)

В управляемом интерфейсе заложена мощная возможность описывать связи реквизитов формы через параметры. Установка параметров связей позволяет ограничить выбор данных так, чтобы целостность данных была обеспечена на этапе ввода. Однако без дополнительного программирования задать можно только самые простые связи. Такие условия связи, как зависимость от реквизита через точку или зависимость через дополнительное отношение, заданное в регистре сведений - уже задать без программирования не получится.

1 стартмани

17.07.2018    60444    24    kalyaka    16    

Интерактивный интерфейс Промо

Рабочее место Работа с интерфейсом v8 1cv8.cf Россия Абонемент ($m)

Обработка (отдельная панель меню), позволяющая настраивать интерфейс пользователя интерактивно (права не настраивает). Мне очень пригодилось, так как приходится прописывать индивидуальный интерфейс, каждому пользователю (а их уже сотни). Выложил 2 версии одна в виде таблицы, вторая в виде выпадающего меню

1 стартмани

29.10.2011    20386    65    Vin_Tik    9    

Иерархическая диаграмма

Работа с интерфейсом v8 1cv8.cf Абонемент ($m)

Концепция диаграммы по иерархической структуре данных, например по номенклатуре (продажи или остатки на складах).

2 стартмани

17.06.2018    16946    19    DrAku1a    6    

Рисуем стрелки в табличном документе

Работа с интерфейсом v8 1cv8.cf Абонемент ($m)

Рисуем стрелки средствами 1С .

1 стартмани

01.06.2018    17821    9    pm74    9    

Программная работа с графическими схемами. Готовое решение

Инструментарий разработчика Универсальные обработки Работа с интерфейсом v8 1cv8.cf Абонемент ($m)

Работоспособное, проверенное на практике, простое и удобное программное управление графическими схемами.

1 стартмани

18.02.2018    21603    23    Yashazz    13    

Цветовые схемы для конфигуратора 1С (Популярные цветовые схемы для C# - теперь и для 1С) (Теперь 8.2 - 8.3) Промо

Работа с интерфейсом v8 1cv8.cf Абонемент ($m)

Тёмные цветовые схемы кода. То, что было доступно всем передовым средствам разработки, теперь доступно и на 1С. 13.12.17 UPD: Теперь работает с платформой 8.3

3 стартмани

07.10.2013    41143    177    Chernov_Dmitriy    82    

Тестирование интерфейса в обычном приложении 8.2 при помощи SikuliX

Инструментарий разработчика Работа с интерфейсом v8 1cv8.cf Абонемент ($m)

Как же не хватает клиента тестирования на платформе 8.2. Не кликнешь на кнопку, не выберешь из списка, не проверишь видит ли надпись пользователь. Воспользуемся внешним инструментом SikuliX, который позволит нам протестировать функционал форм. Данный инструмент легко встраивается в линию сборки и может "дружить" с уже известным многим Open-source продуктами.

1 стартмани

03.01.2018    33491    5    kraynev-navi    41    

Программное формирование форматированной строки в стиле html+inline CSS

Работа с интерфейсом Инструментарий разработчика v8 1cv8.cf Абонемент ($m)

Если вам приходилось работать с форматированными строками программно, то вы знаете, какая это боль. Данное решение облегчает программное формирование таких строк.

1 стартмани

18.11.2017    38662    43    bonv    11    

Программное создание элементов графической схемы (через XSLT)

Практика программирования Работа с интерфейсом v8 1cv8.cf Абонемент ($m)

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

1 стартмани

20.07.2017    23877    66    lazarenko    19    

NativeDraw: Компонента рисования для 1С [V2.6.2] Промо

Разработка внешних компонент Работа с интерфейсом v8 1cv8.cf Абонемент ($m)

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

1 стартмани

13.07.2015    51049    469    ПерваяСистема    147    

Простой редактор плана помещения JavaScript

Практика программирования Работа с интерфейсом v8 1cv8.cf Абонемент ($m)

На ресурсе сейчас очень много решений, которые позволяют редактировать карты, используя географические схемы. Так же много решений, которые позволяют редактировать объекты онлайн веб-карт. Мне же нужно было простое решение, для того чтобы расставить квадратные объекты на плане, показать их пользователю. Ну и распечатать, опять же. Я решил написать простенький редактор на JavaScript с использованием библиотеки Raphael.

1 стартмани

23.11.2016    24844    102    igel9780    22    

Настройка начальной страницы (Рабочего стола)

Работа с интерфейсом Рабочее место Универсальные обработки v8 1cv8.cf Абонемент ($m)

Альтернатива стандартной настройке начальной страницы. В типовой доступны лишь те формы, что явно "разрешены" разработчиком в режиме конфигуратора. Эта обработка позволяет собрать "Рабочий стол" из любых подходящих форм в пользовательском режиме. Без программирования. БСП не используется. Не расширение. Универсальна, т.е. подойдет для любой конфигурации (в т.ч. самописной).

2 стартмани

19.10.2016    42319    240    Erne100    30    

[Расширение] Стартовые страницы. Автозапуск форм при старте 1С. (8.3.9+, без доработки конфигурации)

Инструментарий разработчика Работа с интерфейсом v8 1cv8.cf Абонемент ($m)

Уверен, что в большинстве случаев список справочников, отчетов, обработок (объектов 1С в целом), к которому обращаются пользователи после запуска конфигурации 1С, раз от раза меняется не сильно. Так почему бы немного не упростить процесс открытия часто используемых форм? Данное расширение позволяет настроить автоматическое открытие различных форм объектов сразу после запуска 1С. Список форм настраивается индивидуально для каждого пользователя. Работает на платформе 8.3.9, без доработки конфигурации.

1 стартмани

03.10.2016    23959    89    Artem-B    20    

Подборка иконок для подсистем 1С:8.2, 8.3 (740 шт.) PNG 48х48 Промо

Практика программирования Работа с интерфейсом v8 1cv8.cf Россия Абонемент ($m)

Подборка иконок для подсистем 1С: Предприятие 8.2, 8.3 (УП) в формате PNG 48*48 с сохранением прозрачности.

5 стартмани

19.12.2011    113648    1240    Lesha1C    74    

Конструктор условного оформления

Инструментарий разработчика Работа с интерфейсом v8 1cv8.cf Абонемент ($m)

Иногда требуется сделать отчет, который бы содержал в себе множество показателей. В таком случае в получившейся "портянке" показатели сливаются. Как один из вариантов решения (ну, кроме упрощения отчета) можно рассматривать раскраску показателей в индивидуальные цвета. После нескольких подобных случаев (особенно, когда в уже готовый отчет добавляются или убираются поля) сделал обработку, которая позволяет в режиме предприятия быстро подготовить болванку условного оформления для подобных отчетов.

1 стартмани

27.09.2016    19230    16    Fragster    7    

HTTP-сервис: отчеты [Расширение]

Практика программирования Работа с интерфейсом v8 1cv8.cf Абонемент ($m)

Это HTTP-сервис, который возвращает почти любой отчет в HTML, XLSX или в JSON. Сохраните вариант отчета, получите на него ссылку и можно получить данные без захода в 1С. Работает в конфигурациях на основе БСП 2.3.3+, для отчетов на СКД и в 1С 8.3.8+

2 стартмани

30.08.2016    31277    147    Stepa86    15    

Механизм доп. реквизитов и сведений

Практика программирования Работа с интерфейсом v8 БП2.0 Абонемент ($m)

Как к новому справочнику подключить механизм дополнительных реквизитов и сведений

2 стартмани

23.06.2016    31691    36    piffoff    18    

V8Reader (с расширенным анализом форм) Upd. Промо

Инструментарий разработчика Работа с интерфейсом v8 1cv8.cf Абонемент ($m)

Обработка, позволяющая анализировать и сравнивать файлы отчетов, обработок, конфигураций и обновлений. Имеет мощные инструменты по анализу форм, ролей и ограничений доступа.

1 стартмани

27.01.2012    79980    2452    bambr1975    303