Выгрузить табличную часть в Excel

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

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

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

Пользователь нажимает кнопку «Экспорт в эксель», на сервере формируется файл и передаётся на клиент. На клиенте он открывается приложением по умолчанию для данного формата файла. Код получился кросс платформенный, что в наше время очень актуально.

1С: чтение почты по протоколу IMAP

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

Процедура ЧитнутьНаСервереImap()
	Профиль = Новый ИнтернетПочтовыйПрофиль;
	Профиль.АутентификацияPOP3 = Ложь;
	Профиль.АутентификацияSMTP = Ложь;
	
	// IMAP
	Профиль.ИспользоватьSSLIMAP = Истина;
	Профиль.АдресСервераIMAP = "цукацу-укацука.уцкацук.ru";
	Профиль.ПортIMAP = "993"; 	
	Профиль.ПользовательIMAP = "укацу@укацукау.ru";
	Профиль.ПарольIMAP = "цукацукацук";
	Профиль.ТолькоЗащищеннаяАутентификацияIMAP=Ложь;

	Почта = Новый ИнтернетПочта;
	Сообщ = Новый СообщениеПользователю();

		Почта.Подключиться(Профиль, ПротоколИнтернетПочты.IMAP); //ПротоколИнтернетПочты.POP3		
		заголовки=Почта.ПолучитьЗаголовки();
		если заголовки.Количество()>0 тогда		
			ПоследнийЗаголовок=Новый Массив();
			ПоследнийЗаголовок.Добавить(заголовки[заголовки.Количество()-1]);					
			МассивСообщений = Новый Массив;
			МассивСообщений = Почта.Выбрать(Ложь,ПоследнийЗаголовок);		
			
			ТекстСообщения=МассивСообщений[0].тексты[0].Текст;
			сообщить(ТекстСообщения);
		конецесли;
	
	Почта.Отключиться(); 

	

КонецПроцедуры

Из особенностей логики — сначала вычитываю заголовки, т.к. если почты много, то чтение писем будет ОЧЕНЬ долгим. Далее получаю последний по счету заголовок, и вычитываю текст конкретно уже этого письма.

прочитать сообщение из почтового ящика по протоколу IMAP

Другие статьи по тегу 1С можете почитать тут

Как добавить рабочие дни к дате

Задача добавление рабочих дней к дате (добавить рабочие дни к дате) встречается довольно часто. И штатно должна решаться с помощью стандартного функционала БСП — «Производственный календарь». Например так:

Функция ДобавитьКДатеРабочиеДни(ДатаНач,ЧислоРабочихДней) экспорт
    Запрос=Новый Запрос;
    Запрос.Текст="ВЫБРАТЬ
                 |    ВЫБОР
                 |        КОГДА РегламентированныйПроизводственныйКалендарь.ВидДня = &РабочийДень
                 |                ИЛИ РегламентированныйПроизводственныйКалендарь.ВидДня = &ПредпраздничныйДень
                 |            ТОГДА 1
                 |        ИНАЧЕ 0
                 |    КОНЕЦ КАК ЧислоРабочихДней,
                 |    РегламентированныйПроизводственныйКалендарь.ДатаКалендаря КАК ДатаКалендаря
                 |ПОМЕСТИТЬ ТЗ
                 |ИЗ
                 |    РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК РегламентированныйПроизводственныйКалендарь
                 |ГДЕ
                 |    РегламентированныйПроизводственныйКалендарь.ДатаКалендаря МЕЖДУ &ДатаНач И &ДатаКон
                 |;
                 |
                 |////////////////////////////////////////////////////////////////////////////////
                 |ВЫБРАТЬ
                 |    ТЗ.ДатаКалендаря,
                 |    СУММА(ТЗ1.ЧислоРабочихДней) КАК ЧислоРабочихДней
                 |ПОМЕСТИТЬ ТЗНакопл
                 |ИЗ
                 |    ТЗ КАК ТЗ
                 |        ЛЕВОЕ СОЕДИНЕНИЕ ТЗ КАК ТЗ1
                 |        ПО (ТЗ1.ДатаКалендаря <= ТЗ.ДатаКалендаря)
                 |
                 |СГРУППИРОВАТЬ ПО
                 |    ТЗ.ДатаКалендаря
                 |;
                 |
                 |////////////////////////////////////////////////////////////////////////////////
                 |ВЫБРАТЬ
                 |    МАКСИМУМ(ТЗ.ДатаКалендаря) КАК ДатаКалендаря
                 |ИЗ
                 |    ТЗНакопл КАК ТЗ
                 |ГДЕ
                 |    ТЗ.ЧислоРабочихДней = &ЧислоРабочихДней";
    Запрос.УстановитьПараметр("ДатаНач",             ДатаНач);
    ЧислоНедель = Цел(ЧислоРабочихДней/5+0.5);
    ЧислоВыходныхДней = ЧислоНедель*2;
    МаксимальноеКоличествоПраздничныхДнейПодряд = 8; //РождественскиеКаникулы
    ДатаКон = ДатаНач+(ЧислоВыходныхДней+ЧислоРабочихДней+МаксимальноеКоличествоПраздничныхДнейПодряд)*24*60*60;
    Запрос.УстановитьПараметр("ДатаКон",ДатаКон);
    Запрос.УстановитьПараметр("ЧислоРабочихДней",ЧислоРабочихДней);
    Запрос.УстановитьПараметр("РабочийДень",         Перечисления.ВидыДнейПроизводственногоКалендаря.Рабочий);
    Запрос.УстановитьПараметр("ПредпраздничныйДень", Перечисления.ВидыДнейПроизводственногоКалендаря.Предпраздничный);
    Выборка = Запрос.Выполнить().Выбрать();
    Результат = 0;
    Если Выборка.Следующий() Тогда
        Результат = КонецДня(Выборка.ДатаКалендаря)+1; 
    Конецесли;    
    Возврат Результат;
КонецФункции  

Однако не всё же не все конфигурации содержат производственный календарь. Например почему-то обделено Делопроизводство 2.0. Что-бы не городить огород,, решил задачу «в лоб», без учёта праздничных дней — просто проверяю выпадение даты на субботу-воскресенье. В моём случае этого хватило.

Функция ДобавитьКДатеРабочиеДни(ДатаПроверки,дней)
    добавлено=0;
	пока добавлено<>дней цикл
	  ДатаПроверки=ДатаПроверки+86400;	         
	  Если ДеньНедели(ДатаПроверки) <> 6 ИЛИ ДеньНедели(ДатаПроверки) <> 7 Тогда
		  добавлено=добавлено+1;
	  конецесли;	  
     конеццикла;	
  	Возврат ДатаПроверки;
КонецФункции
добавить рабочие дни к дате

Другие статьи по теме 1С, можно почитать тут

1С: передать файл с сервера на клиент

Задача: Открыть файл прикрепленный к справочнику на клиенте приложением по умолчанию (передать файл с сервера на клиент)

Решение: любой файл который «прикреплен» к справочнику, если используется БСП , на самом деле находится в справочнике Файлы. Это для старых версий БСП. В новых версиях имя справочника носит шаблонное имя [ИмяСправочника]ПрисоединенныеФайлы. В обоих вариантах у этик справочников есть реквизит «Владелец файла». Вот по нему и получим самый первый прикрепленный файл.

&НаСервере
Функция ОткрытьФайлНаСервере()    		    
			фф="";
			Запрос = Новый Запрос;
			Запрос.Текст = 
				"ВЫБРАТЬ ПЕРВЫЕ 1
				|	Файлы.Ссылка КАК Ссылка,
				|	Файлы.ПолноеНаименование КАК ПолноеНаименование,
				|	Файлы.ТекущаяВерсияПутьКФайлу КАК ТекущаяВерсияПутьКФайлу,
				|	Файлы.ТекущаяВерсияТом.ПолныйПутьWindows КАК ТекущаяВерсияТомПолныйПутьWindows,
				|	Файлы.ГлавныйФайл КАК ГлавныйФайл,
				|	Файлы.ТекущаяВерсияРасширение КАК ТекущаяВерсияРасширение,
				|	Файлы.Наименование КАК Наименование
				|ИЗ
				|	Справочник.Файлы КАК Файлы
				|ГДЕ
				|	Файлы.ВладелецФайла = &ВладелецФайла
				|	И Файлы.ПометкаУдаления = ЛОЖЬ";	
			Запрос.УстановитьПараметр("ВладелецФайла", объект.ДокОб);	
			РезультатЗапроса = Запрос.Выполнить();	
			ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();	
			Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
                сообщить(ВыборкаДетальныеЗаписи.Ссылка);
				фф=ВыборкаДетальныеЗаписи.ТекущаяВерсияТомПолныйПутьWindows+ВыборкаДетальныеЗаписи.ТекущаяВерсияПутьКФайлу;
			КонецЦикла;		

			если фф<>"" тогда
				Двоичное=Новый ДвоичныеДанные(фф);
				Адрес=ПоместитьВоВременноеХранилище(Двоичное,ЭтаФорма.УникальныйИдентификатор);
				Возврат Новый Структура("error,address,filename",false,Адрес,ВыборкаДетальныеЗаписи.Наименование+"."+ВыборкаДетальныеЗаписи.ТекущаяВерсияРасширение);	
			иначе
				Возврат Новый Структура("error,address,filename",true);
			конецесли			
КонецФункции

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

&НаКлиенте
Процедура ОткрытьФайл(Команда)
	рез=ОткрытьФайлНаСервере();
	если рез.error=false тогда
		Двоичное=ПолучитьИзВременногоХранилища(рез.address);			
		ИмяФайла = КаталогВременныхФайлов() + рез.filename;		
		Двоичное.Записать(ИмяФайла);
		ЗапуститьПриложение(ИмяФайла);
	конецесли;

КонецПроцедуры
передать файл с сервера на клиент

Другие мои статьи по теме 1С тут

Проверка безопасности пользователей 1С

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

В моём случае возникла необходимость регулярно мониторить служебные учётные данные. Количество разработчиков большое. Количество http и web сервисов не большое, но постоянно растёт, т.к. мы придерживаюсь принципа: один сервис — одна учётка для доступа. Делается это для того чтобы было удобнее логировать и отслеживать кто что и как. Соответственно необходимо чтобы эти служебные пользователи имели строго определенные доступы, и не имели возможность непосредственного входа в 1С через толстый и тонкий клиенты.

После калькуляции требований безопасности я выявил следующие показатели для того чтобы считать учётную запись «неблагонадёжной»:

  • нет доменной авторизации
  • разрешен вход в 1с (галочка «Доступ к информационной базе разрешен» в справочнике Пользователи)
  • у пользователя включены роли ЗапускВебКлиента, ЗапускТолстогоКлиента, ЗапускВнешнегоСоединения
  • При ответе «Да» на все три условия, пользователя помещаю в соответствующий список.
  • Кроме того дополнительно провожу проверку, что в правах одной из ролей есть права: ЗапускВебКлиента, ЗапускТолстогоКлиента, ЗапускВнешнегоСоединения

В итоге родил такую обработку:

Процедура СК_ГР_ПроверкаБезопасностиПользователя() экспорт
	УстановитьПривилегированныйРежим(Истина);
	Выборка = ПользователиИнформационнойБазы.ПолучитьПользователей(); 
	МассивДляОтчета=Новый Массив();
	данные="";   
	бд=НСтр(СтрокаСоединенияИнформационнойБазы(), "Ref"); 
	Для Каждого ЭлементМассива Из Выборка Цикл 
		если ЭлементМассива.АутентификацияОС=ложь тогда
			если ЭлементМассива.АутентификацияСтандартная=истина тогда				
				инф=Новый Структура("полноеимя,имя,email,датапароля,показыватьвспискевыбора,роли,пользователь,ЗапускВебКлиента,ЗапускТолстогоКлиента,ЗапускТонкогоКлиента,ЗапускВнешнегоСоединения");				
				инф.полноеимя=ЭлементМассива.ПолноеИмя;
				инф.имя=ЭлементМассива.Имя;
				инф.email=ЭлементМассива.АдресЭлектроннойПочты;
				инф.датапароля=ЭлементМассива.ДатаУстановкиПароля;
				инф.показыватьвспискевыбора=ЭлементМассива.ПоказыватьВСпискеВыбора;
				инф.роли="";
				
				ЕстьПароль = ЭлементМассива.ПарольУстановлен; 
				Роли = ЭлементМассива.Роли; 		
				Для Каждого Роль Из Роли Цикл 					
					если ПравоДоступа("ВебКлиент",Метаданные,Роль) тогда
						инф.роли=инф.роли+Роль.Имя+", ";
					иначеесли ПравоДоступа("ВнешнееСоединение",Метаданные,Роль) тогда
						инф.роли=инф.роли+Роль.Имя+", ";
					иначеесли ПравоДоступа("ТолстыйКлиент",Метаданные,Роль) тогда
						инф.роли=инф.роли+Роль.Имя+", ";
					иначеесли ПравоДоступа("ТонкийКлиент",Метаданные,Роль) тогда
						инф.роли=инф.роли+Роль.Имя+", ";
					конецесли;						
				КонецЦикла; 				
				поль=Справочники.Пользователи.НайтиПоРеквизиту("ИдентификаторПользователяИБ",ЭлементМассива.УникальныйИдентификатор);
				    ЗапускРоль="";
					если поль<>Справочники.Пользователи.ПустаяСсылка() тогда
						инф.ЗапускВебКлиента=УправлениеДоступом.ЕстьРоль("ЗапускВебКлиента",, поль);					
						если инф.ЗапускВебКлиента=истина тогда
							ЗапускРоль=ЗапускРоль+"Веб, ";	
						конецесли;
						инф.ЗапускТолстогоКлиента=УправлениеДоступом.ЕстьРоль("ЗапускТолстогоКлиента",, поль);
						если инф.ЗапускТолстогоКлиента=истина тогда
							ЗапускРоль=ЗапускРоль+"Толстый, ";	
						конецесли;						
						инф.ЗапускТонкогоКлиента=УправлениеДоступом.ЕстьРоль("ЗапускТонкогоКлиента",, поль);
						если инф.ЗапускТонкогоКлиента=истина тогда
							ЗапускРоль=ЗапускРоль+"Тонкий, ";	
						конецесли;						
						инф.ЗапускВнешнегоСоединения=УправлениеДоступом.ЕстьРоль("ЗапускВнешнегоСоединения",, поль);
						если инф.ЗапускВнешнегоСоединения=истина тогда
							ЗапускРоль=ЗапускРоль+"Внешние, ";	
						конецесли;
						
					конецесли;				
								
				инф.пользователь=поль.Наименование;				
				МассивДляОтчета.Добавить(инф);
				
				данные=данные+"<tr>";
				данные=данные+" <td>"+инф.полноеимя+"</td>";
				данные=данные+" <td>"+инф.имя+"</td>";
				данные=данные+" <td>"+инф.пользователь+"</td>";
				данные=данные+" <td>"+инф.email+"</td>";
				данные=данные+" <td>"+инф.датапароля+"</td>";
				данные=данные+" <td>"+инф.показыватьвспискевыбора+"</td>";				
				данные=данные+" <td>"+ЗапускРоль+"</td>";
				данные=данные+" <td>"+инф.роли+"</td>";
				данные=данные+"</tr>";
				
			Конецесли;
		Конецесли;
	КонецЦикла;
		
	если МассивДляОтчета.Количество()>0 тогда
		 			
		 	тело="<style>td {border: 1px solid;} th{border: 1px solid;} table.table {word-wrap:true;border-collapse: collapse;border-spacing: 0;}table.table > thead > tr > th {font-size: 14px;font-weight: normal;padding-top: 7px;padding-bottom: 7px;}.table > thead > tr > th {vertical-align: bottom;border-bottom: 2px solid #ddd;}table.table th {background-color: #153e76;}</style>";						
			тело=тело+"Критерии попадания в этот список: отключена доменная авторизация, разрешен вход в 1С<br/>";			
		 	тело=тело+"<strong>Подозрительные учётки</strong>: <br/>";
    		тело=тело+"<table class='table'>";
    		тело=тело+"  <thead>";
    		тело=тело+"    <tr>";
    		тело=тело+"     <th scope='col'> Полное имя</th>";
			тело=тело+"     <th scope='col'> Имя</th>";
			тело=тело+"     <th scope='col'> Пользователь</th>";			
			тело=тело+"     <th scope='col'> Email</th>";
			тело=тело+"     <th scope='col'> Дата пароля</th>";
			тело=тело+"     <th scope='col'> В списке выбора</th>";
			тело=тело+"     <th scope='col'> Вид запуска</th>";
			тело=тело+"     <th scope='col'> Роли с доступом в 1С</th>";
    		тело=тело+"   </tr>";
    		тело=тело+" </thead>";
    		тело=тело+" <tbody>";    		 
		 	тело=тело+данные;		 
		 	тело=тело+"  </tbody>";
    		тело=тело+"</table>";

						
		 emails=Новый Массив();	
		 emails.Добавить("цкуаука@куауцкацук.ru");
		 
		 для каждого email из emails цикл
			 если email<>"" тогда
				 попытка
	 			 		ПараметрыПисьма = Новый Структура("Кому, Тема, Тело,ТипТекста", email, "Подозрительные учётки в БД: "+бд, тело,"HTML");
						если бд="укму" тогда
						 УчетнаяЗаписьПочты = РаботаСПочтовымиСообщениями.ПолучитьСистемнуюУчетнуюЗапись();						
				 		 РаботаСПочтовымиСообщениями.ОтправитьСообщение(УчетнаяЗаписьПочты, ПараметрыПисьма);
					    иначеесли бд="куепуке" тогда
						 УчетнаяЗаписьПочты = РаботаСПочтовымиСообщениями.ПолучитьСистемнуюУчетнуюЗапись();
						 РаботаСПочтовымиСообщениями.ОтправитьСообщение(УчетнаяЗаписьПочты, ПараметрыПисьма);
					    иначеесли бд="укепуке" тогда					 
						 РаботаСПочтовымиСообщениями.ОтправитьПочтовоеСообщение(РаботаСПочтовымиСообщениями.СистемнаяУчетнаяЗапись(),ПараметрыПисьма);					 					 
					    иначеесли бд="куепук" тогда					 
						 РаботаСПочтовымиСообщениями.ОтправитьПочтовоеСообщение(РаботаСПочтовымиСообщениями.СистемнаяУчетнаяЗапись(),ПараметрыПисьма);					 
					    конецесли;						 
					исключение
						ЗаписьЖурналаРегистрации("Ошибка", УровеньЖурналаРегистрации.Ошибка,,ОписаниеОшибки(),);			
				 конецпопытки;
	 		 конецесли;									 
	     конеццикла;		 		 
	конецесли;
	  УстановитьПривилегированныйРежим(ложь);
КонецПроцедуры

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

проверка безопасности пользователей 1С

Почитайте еще по теме 1С тут

1 7 8 9 10 11 50