1С: Отслеживание обновления конфигурации

Задача: Необходимо уведомлять на почту заинтересованных лиц об обновлении конфигурации 1С

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

&НаСервере
Процедура ПроверкаОбновленияКонфигурации() экспорт	
   // получаем таблицу когда меняли конфигурацию	
   ЖурналОбновленияКонфигурации = Новый ТаблицаЗначений;   
   СтатусыТранзакций = Новый Массив;
   СтатусыТранзакций.Добавить(СтатусТранзакцииЗаписиЖурналаРегистрации.Зафиксирована);
   СтатусыТранзакций.Добавить(СтатусТранзакцииЗаписиЖурналаРегистрации.НетТранзакции);       
   МетаданныеМассив = Новый Массив;  
   МассивСобытий = Новый Массив;
   МассивСобытий.Добавить("_$InfoBase$_.DBConfigUpdate");      
   ФильтрЗаполнения = Новый Структура;
   ФильтрЗаполнения.Вставить("ДатаНачала", НачалоДня(ТекущаяДата()));
   ФильтрЗаполнения.Вставить("ДатаОкончания", КонецДня(ТекущаяДата()));
   ФильтрЗаполнения.Вставить("Метаданные", МетаданныеМассив);
   ФильтрЗаполнения.Вставить("Событие", МассивСобытий);
   ФильтрЗаполнения.Вставить("Комментарий", "Регистрация конфигурации изменена");   
   ВыгрузитьЖурналРегистрации(ЖурналОбновленияКонфигурации, ФильтрЗаполнения,"Дата, Событие, Метаданные, Данные, ПредставлениеДанных,Комментарий,Пользователь");
   
   ДатаПоследнегоОбновления=неопределено;
   Обновлятор=неопределено;
   если ЖурналОбновленияКонфигурации.Количество()>0 тогда
	   Зап=ЖурналОбновленияКонфигурации[ЖурналОбновленияКонфигурации.Количество()-1];
	   ДатаПоследнегоОбновления=Зап[0];
       УИНПользователя = Новый УникальныйИдентификатор(Зап[2]);
	   ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору(УИНПользователя);
   конецесли;	   
   если ДатаПоследнегоОбновления<>неопределено тогда	   
	   //Получаем таблицу когда уведомляли об изменнии конфигурации
	   ЖурналУведомленийОбОбновленииКонфигурации = Новый ТаблицаЗначений;   
	   СтатусыТранзакций = Новый Массив;
	   СтатусыТранзакций.Добавить(СтатусТранзакцииЗаписиЖурналаРегистрации.Зафиксирована);
	   СтатусыТранзакций.Добавить(СтатусТранзакцииЗаписиЖурналаРегистрации.НетТранзакции);       
	   МетаданныеМассив = Новый Массив;  
	   МассивСобытий = Новый Массив;
	   МассивСобытий.Добавить("UpdateConfigAlert");      
	   ФильтрЗаполнения = Новый Структура;
	   ФильтрЗаполнения.Вставить("ДатаНачала", НачалоДня(ТекущаяДата()));
	   ФильтрЗаполнения.Вставить("ДатаОкончания", КонецДня(ТекущаяДата()));
	   ФильтрЗаполнения.Вставить("Метаданные", МетаданныеМассив);
	   ФильтрЗаполнения.Вставить("Событие", МассивСобытий);
	   ВыгрузитьЖурналРегистрации(ЖурналУведомленийОбОбновленииКонфигурации, ФильтрЗаполнения,"Дата, Событие, Метаданные, Данные, ПредставлениеДанных,Комментарий,Пользователь");
	   ДатаПоследнегоУведомления=неопределено;
	   если ЖурналУведомленийОбОбновленииКонфигурации.Количество()>0 тогда
		   Зап=ЖурналУведомленийОбОбновленииКонфигурации[ЖурналУведомленийОбОбновленииКонфигурации.Количество()-1];
		   ДатаПоследнегоУведомления=Зап[5];
	   конецесли;	   	   	   
	   // Писнем в журнал данные, когда последний раз уведомляли об изменениях заинтересованных лиц
	   если ДатаПоследнегоУведомления=неопределено или ДатаПоследнегоУведомления<>ДатаПоследнегоОбновления тогда
	    ЗаписьЖурналаРегистрации("UpdateConfigAlert", УровеньЖурналаРегистрации.Информация, ,ДатаПоследнегоОбновления, "Чуток обновили конфу", РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная);
		МассивЗаинтересованыхЛиц=Новый Массив();
		МассивЗаинтересованыхЛиц.Добавить("ауцук@укацук.ru");		
		ИмяБазы = СоединенияИБКлиентСервер.ПутьКИнформационнойБазе();
		ТелоПисьма="<b>Внимание!</b><br/>Наш коллега "+Строка(ПользовательИБ)+" успешно выполнил обновление конфигурации.<br/>База: "+ИмяБазы+"<br/>Дата: "+Строка(ДатаПоследнегоОбновления)+"<br/><br/>Ура товарищи!";
		
		для каждого email из МассивЗаинтересованыхЛиц цикл
		  	попытка		
				УчетнаяЗаписьПочты = РаботаСПочтовымиСообщениями.ПолучитьСистемнуюУчетнуюЗапись();
				ПараметрыПисьма = Новый Структура("Кому, Тема, Тело,ТипТекста", email, "Было обновление конфигурации 1С", ТелоПисьма,"HTML");
				РаботаСПочтовымиСообщениями.ОтправитьСообщение(УчетнаяЗаписьПочты, ПараметрыПисьма);				
			исключение   
				ЗаписьЖурналаРегистрации("СК_ГР.МониторингИзмененияКонфигурации", УровеньЖурналаРегистрации.Ошибка,,ОписаниеОшибки(),);		
			конецпопытки;
		конеццикла;
	   конецесли;
		
	конецесли;
	   
КонецПроцедуры

1С: Фильтры с выбором значения в шапке отчета СКД

Заметил в одном из отчетов на СКД замечательную функцию: щелкаешь по столбику шапки, и выходит окошко в котором можно пофильтровать по результату. Однако..подумал я. Штатно такого в СКД нет. Чуть порывшись в коде модуля, нашел что за это отвечает следующая конструкция:


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

В результате и получается:

Что вышеприведенный код делает, в душе не понимаю (недолюбливаю СКД, потому редко его касаюсь). Как и то, почему это всё нельзя было сделать чтоб сразу «было» из «коробки».

1С: Поиск в списке выбора

Вообще поиск в списке выбора уже в 1С реализован штатно. Но! как всегда со своими нюансами (видимо в угоду универсальности). А именно: поиск ведется только по началу строки. Если же хочется чтоб поиск был более «умный». то можно навесить на событие «АвтоПодбор» свою реализацию. Например такую:

&НаКлиенте
Процедура ШаблонДокументаАвтоПодбор(Элемент, Текст, ДанныеВыбора, ПараметрыПолученияДанных, Ожидание, СтандартнаяОбработка)
	
	Результат=Новый СписокЗначений();
	для каждого стр из Элементы.ШаблонДокумента.СписокВыбора цикл
		если СтрНайти(ВРег(Строка(стр.Представление)),ВРег(Текст))<>0 тогда
			Результат.Добавить(стр.Значение,стр.Представление,стр.Пометка,стр.Картинка);
		конецесли;
	конеццикла;	
	ДанныеВыбора=Результат;
	СтандартнаяОбработка = Ложь;
	
КонецПроцедуры

1С: Вычисляемые поля в СКД

Избегаю делать отчеты через СКД, потому что спустя какое-то время, сложный отчет превращается в жуткую абракадабру, в которой потом разобраться очень трудно. Слишком всё запутано, слишком много галочек, настроек и прочего. Да, можно сделать почти всё, но для этого нужно СКД знать досконально, и пользоваться им каждый день, чтобы не забыть все нюансы. Когда же сам пишешь отчет, а не через СКД, то тут и комментарии доложишь, и логику попроще сделаешь (пусть и в ущерб производительности). Вот и сейчас, пришлось покопаться в СКД, чтобы вспомнить, как например сделать трюк, с размещением периода дат в одной ячейке. Типа вот так:

Ну а реализация на самом деле простая вышла:

1С: Проверка на пустое значение в запросе

На самом деле это не так просто сделать. Есть несколько вариантов, для разных типов значений:

  • Дата: СК_ИскВходящий.ДатаВступленияРешенияВСилу = ДАТАВРЕМЯ(1, 1, 1)
  • Если тип значения не составной, то: Аппеляция.ВидОбжалования ЕСТЬ NULL
  • А вот с составным весело — почему то сравнение с NULL не работает в этом случае. Приходится использовать сравнение типов. Как-то так у меня вышло:
ВЫБОР
	КОГДА СК_ИскВходящий.Обжалование = ЛОЖЬ
			И (ТИПЗНАЧЕНИЯ(СК_ИскВходящий.ИтоговыйСудебныйАкт) <> ТИП(СТРОКА)
				И ТИПЗНАЧЕНИЯ(СК_ИскВходящий.ИтоговыйСудебныйАкт) <> ТИП(Перечисление.СК_ГР_ИтоговыйСудебныйАкт))
		ТОГДА "Находится на рассмотрении в суде первой инстанции"
	КОГДА СК_ИскВходящий.Обжалование = ЛОЖЬ
			И СК_ИскВходящий.ДатаВступленияРешенияВСилу = ДАТАВРЕМЯ(1, 1, 1)
			И СК_ИскВходящий.ДатаСудебногоАкта > ДАТАВРЕМЯ(1, 1, 1)
			И СК_ИскВходящий.ИтоговыйСудебныйАкт = ЗНАЧЕНИЕ(Перечисление.СК_ГР_ИтоговыйСудебныйАкт.РешениеОбУдовлетворенииТребований)
		ТОГДА "Вынесен судебный акт, не вступил в законную силу"
	КОГДА СК_ИскВходящий.Обжалование = ИСТИНА
			И НЕ Аппеляция.ВидОбжалования ЕСТЬ NULL
			И СК_ИскВходящий.ИтоговыйСудебныйАкт = ЗНАЧЕНИЕ(Перечисление.СК_ГР_ИтоговыйСудебныйАкт.РешениеОбУдовлетворенииТребований)
			И СК_ИскВходящий.ДатаСудебногоАкта > ДАТАВРЕМЯ(1, 1, 1)
			И СК_ИскВходящий.ДатаВступленияРешенияВСилу = ДАТАВРЕМЯ(1, 1, 1)
		ТОГДА "Вынесен судебный акт, обжалуется в апелляционной инстанции"
	КОГДА ТИПЗНАЧЕНИЯ(СК_ИскВходящий.ИтоговыйСудебныйАкт) <> ТИП(СТРОКА)
			И ТИПЗНАЧЕНИЯ(СК_ИскВходящий.ИтоговыйСудебныйАкт) <> ТИП(Перечисление.СК_ГР_ИтоговыйСудебныйАкт)
			И СК_ИскВходящий.ДатаСудебногоАкта > ДАТАВРЕМЯ(1, 1, 1)
			И СК_ИскВходящий.ДатаВступленияРешенияВСилу > ДАТАВРЕМЯ(1, 1, 1)
			И НЕ Кассация.ВидОбжалования ЕСТЬ NULL
			И РАЗНОСТЬДАТ(&ТекДата, СК_ИскВходящий.ДатаСудебногоАкта, МЕСЯЦ) < 3
		ТОГДА "Судебный акт вступил в законную силу, но не вышел срок для кассационного обжалования"
	КОГДА СК_ИскВходящий.ИтоговыйСудебныйАкт = ЗНАЧЕНИЕ(Перечисление.СК_ГР_ИтоговыйСудебныйАкт.РешениеОбУдовлетворенииТребований)
			И СК_ИскВходящий.ДатаСудебногоАкта > ДАТАВРЕМЯ(1, 1, 1)
			И СК_ИскВходящий.ДатаВступленияРешенияВСилу = ДАТАВРЕМЯ(1, 1, 1)
			И НЕ Кассация.ВидОбжалования ЕСТЬ NULL
			И Кассация2Инстанция.ДатаВозвратаИзСуда = ДАТАВРЕМЯ(1, 1, 1)
		ТОГДА "Вынесен судебный акт, обжалуется в кассационной инстанции"
	ИНАЧЕ "Неопределено"
КОНЕЦ

Тут в принципе можно подсмотреть все варианты

1 2 3 54