Делаем из СКД 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
28.02.20
1
.cf 22,72Kb 1 Скачать

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

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

См. также

СКД: красивые надписи в заголовках колонок

Отчеты и формы Программист Архив с данными v8 v8::СКД УПП1 Россия Windows Абонемент ($m) Практика программирования Работа с интерфейсом

Необходимо немного исправить вывод надписей в заголовках колонок, сделать более читаемый вариант. Как это сделать?

2 стартмани

27.02.2020    5349    5    wowik    36       

1C:Предприятие для программистов: Расчетные задачи (зарплата). Онлайн-интенсив с 01 по 17 июня 2020 г. Промо

Данный онлайн-курс предусматривает изучение механизмов платформы “1С:Предприятие”, которые предназначены для автоматизации периодических расчетов, а именно - для расчета зарплаты. Курс предназначен для тех, кто уже имеет определенные навыки конфигурирования и программирования в системе “1С:Предприятие”, а также для опытных пользователей прикладного решения “1С:Зарплата и управление персоналом” и прочих прикладных решений, в которых реализован функционал расчета зарплаты.

4900 рублей

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

Инструменты и обработки Программист Внешняя обработка (ert,epf) v8 v8::УФ 1cv8.cf Абонемент ($m) БСП (Библиотека стандартных подсистем) Работа с интерфейсом

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

1 стартмани

27.12.2019    4113    9    1sig    12       

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

Инструменты и обработки Программист Внешняя обработка (ert,epf) v8 1cv8.cf Абонемент ($m) Работа с интерфейсом

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

1 стартмани

23.12.2019    3828    31    XilDen    3       

Программы для исполнения 54-ФЗ Промо

С 01.02.2017 контрольно-кассовая техника должна отправлять электронные версии чеков оператору фискальных данных - правила установлены в 54-ФЗ ст.2 п.2. Инфостарт предлагает подборку программ, связанных с применением 54-ФЗ, ККТ и электронных чеков.

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

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

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

1 стартмани

17.12.2019    4319    2    azhilichev    5       

"Живые" картинки со Snap.SVG

Статья Программист Конфигурация (md, cf) v8 Абонемент ($m) Практика программирования WEB Работа с интерфейсом

В статье рассмотрен пример использования http-сервисов для визуализации данных

1 стартмани

24.10.2019    7570    15    blackhole321    4       

Подборка программ для взаимодействия с ЕГАИС Промо

ЕГАИС (Единая государственная автоматизированная информационная система) - автоматизированная система, предназначенная для государственного контроля за объёмом производства и оборота этилового спирта, алкогольной и спиртосодержащей продукции. Инфостарт рекомендует подборку проверенных решений для взаимодействия с системой.

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

Инструменты и обработки Программист Внешняя обработка (ert,epf) v8 ERP2 УТ11 Россия Абонемент ($m) Работа с интерфейсом

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

1 стартмани

09.09.2019    6370    8    bmk74    1       

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

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

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

1 стартмани

12.08.2019    7714    5    Yashazz    18       

Подборка решений для взаимодействия со ФГИС «Меркурий» Промо

С 1 июля 2019 года все компании, участвующие в обороте товаров животного происхождения, должны перейти на электронную ветеринарную сертификацию (ЭВС) через ФГИС «Меркурий». Инфостарт предлагает подборку программ, связанных с этим изменением.

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

Инструменты и обработки Программист Конфигурация (md, cf) v8 1cv8.cf Абонемент ($m) Работа с интерфейсом

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

1 стартмани

09.08.2019    10219    14    rpgshnik    39       

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

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

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

1 стартмани

09.08.2019    10079    12    nagaitseff    6       

Программы для исполнения 488-ФЗ: Маркировка товаров Промо

1 января 2019 года вступил в силу ФЗ от 25.12.2018 № 488-ФЗ о единой информационной системе маркировки товаров с использованием контрольных (идентификационных) знаков, который позволяет проследить движение товара от производителя до конечного потребителя. Инфостарт предлагает подборку программ, связанных с применением 488-ФЗ и маркировкой товаров.

Изменяющееся контекстное меню в 1С 8.3

Статья Программист Архив с данными v8 v8::УФ Абонемент ($m) Практика программирования Работа с интерфейсом Разработка

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

1 стартмани

06.08.2019    9513    1    signum2009    15       

Шпаргалка разработчика для работы с формами

Отчеты и формы Программист Архив с данными v8 Россия Абонемент ($m) Работа с интерфейсом

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

3 стартмани

31.10.2018    11434    75    ELAM    3       

Базовый курс по обмену данными в системе 1С:Предприятие. Онлайн-интенсив с 12 по 28 мая 2020 г. Промо

Данный онлайн-курс предусматривает изучение механизмов платформы “1С:Предприятие”, обеспечивающих обмен данными между различными прикладными 1С-решениями и взаимодействие с другими информационными системами. Курс предназначен для тех, кто уже имеет определенные навыки конфигурирования и программирования в системе “1С:Предприятие”.

5500 рублей

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

Инструменты и обработки Программист Расширение (cfe) v8 1cv8.cf Абонемент ($m) Работа с интерфейсом

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

1 стартмани

27.10.2018    12799    11    tormozit    28       

Онлайн-курс «Автоматизация процессов управления МТО: методика сбора и формализации требований» с 1 апреля по 13 мая 2020 года. Промо

Цель курса - повысить полноту и качество сбора и формализации требований к автоматизации процессов управления материально-техническим обеспечением. Курс основан на процессном подходе, позволяет в полном объеме выявить и учесть все факторы, влияющие на специфику процессов управления МТО. Участники курса получают теоретические знания в области организации процессов управления МТО и готовый инструментарий для сбора и формализации требований по автоматизации этих процессов (шаблоны, опросники, модели).

40000 рублей

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

Инструменты и обработки Программист Внешняя обработка (ert,epf) v8 1cv8.cf Абонемент ($m) Работа с интерфейсом

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

1 стартмани

31.07.2018    18908    138    Plotks2017    27       

Онлайн-курс "Подготовка к экзамену 1С:Эксперт и 1С:Профессионал по технологическим вопросам" с 7 по 24 апреля 2020 г. Промо

На курсе вы получите практические навыки решения задач производительности 1С, в том числе характерных для высоконагруженных информационных систем (более 1000 пользователей). Подготовка к экзамену – только одна из составляющих курса. 70% слушателей приходят за знаниями, которые позволят расти и зарабатывать, делать сложные задачи на крупных проектах.

16450 рублей

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

Инструменты и обработки Программист Внешняя обработка (ert,epf) v8 Абонемент ($m) Практика программирования Работа с интерфейсом

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

1 стартмани

24.07.2018    11021    18    WalterMort    27       

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

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

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

1 стартмани

17.07.2018    31682    17    kalyaka    16       

Готовые переносы данных из различных конфигураций 1C Промо

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

Управление состоянием формы через конечный автомат

Статья Программист Конфигурация (md, cf) v8 Россия Абонемент ($m) Практика программирования Работа с интерфейсом

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

1 стартмани

19.06.2018    12803    12    kalyaka    37       

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

Инструменты и обработки Программист Бизнес-аналитик Руководитель проекта Внешняя обработка (ert,epf) v8 1cv8.cf Абонемент ($m) Работа с интерфейсом

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

2 стартмани

17.06.2018    10060    16    DrAku1a    5       

DevOps для 1С. Онлайн-курс проходит с 16 апреля по 11 июня 2020 года. Промо

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

12000 рублей

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

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

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

1 стартмани

18.02.2018    14296    16    Yashazz    13       

Новый раздел на Инфостарте - Electronic Software Distribution Промо

Инфостарт напоминает: на нашем сайте можно купить не только ПО, связанное с 1С. В нашем арсенале – ESD-лицензии на ПО от ведущих вендоров: Microsoft, Kaspersky, ESET, Dr.Web, Аскон и другие.

  • Низкие цены, без скрытых платежей и наценок
  • Оперативная отгрузка
  • Возможность оплаты с личного счета (кешбек, обмен стартмани на рубли и т.п.)
  • Покупки идут в накопления для получения скидочных карт лояльности Silver (5%) и Gold (10%)

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

Инструменты и обработки Системный администратор Программист Архив с данными v8 1cv8.cf Windows Абонемент ($m) Инструментарий разработчика Работа с интерфейсом

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

1 стартмани

03.01.2018    24032    2    kraynev-navi    40       

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

Инструменты и обработки Программист Внешняя обработка (ert,epf) v8 1cv8.cf Абонемент ($m) Работа с интерфейсом Инструментарий разработчика

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

1 стартмани

18.11.2017    24480    29    bonv    9       

Базовый курс для начинающих 1С-программистов. Онлайн-интенсив со 2 июня по 2 июля 2020 г. Промо

Данный онлайн-курс является начальной ступенью по изучению базовых принципов программирования в системе “1С:Предприятие” и предназначен для обучения 1С-программированию “с нуля”.

4500-9500 рублей

Размеры управляемой формы

Статья Программист Внешняя обработка (ert,epf) v8 1cv8.cf Абонемент ($m) Практика программирования Работа с интерфейсом Универсальные функции

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

1 стартмани

08.10.2017    22608    58    json    8       

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

Инструменты и обработки Программист Внешняя обработка (ert,epf) v8 1cv8.cf Абонемент ($m) Практика программирования Работа с интерфейсом

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

1 стартмани

20.07.2017    17035    54    lazarenko    16