1с: Формулы в макете

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

Решение: в макете формулы вставить не возможно, из-за ограничений платформы 1С. Однако есть другой пусть — вставить формулы уже после формирования файла xlsx. Файл этого формата, по сути zip архив, в котором содержаться файлы xml с данными листов. Поэтому вполне возможно, проставив в макете в нужные формулы в текстовом формате, заменить их на «настоящие» уже в самом файле

Примечание: Задача решена на основе разработок описанных тут и тут. К себе на сайт утащил наработки, потому что-то с «интернетом творится что-то странное» — сегодня статьи есть, а завтра их уже снесли или разместили в платный раздел.

Всю работу по преобразованию разместил в отдельны модуль:


// Процедура - Извлечь архив, распаковывает ZIP-архив в указанный каталог
Процедура ИзвлечьАрхив(ПутьФайла, ПутьКаталога) Экспорт
   ДДФайла = Новый ДвоичныеДанные(ПутьФайла);
   Поток = Новый ПотокВПамяти(ПолучитьБуферДвоичныхДанныхИзДвоичныхДанных(ДДФайла));
   Попытка
       Архив = Новый ЧтениеZipФайла(Поток);
       Архив.ИзвлечьВсе(ПутьКаталога, РежимВосстановленияПутейФайловZIP.Восстанавливать);
       Архив.Закрыть();
   Исключение
       Сообщить("Ошибка при извлечении архива: " + ПутьФайла);
   КонецПопытки;
   Поток.Закрыть();                                                                                              
КонецПроцедуры

// Процедура - Собрать архив, упаковывает файлы из каталога в ZIP-архив
Процедура СобратьАрхив(ПутьКаталога, ПутьФайла) Экспорт
   Архив = Новый ЗаписьZipФайла(ПутьФайла);
   Архив.Добавить(ПутьКаталога + "\*.*",
   РежимСохраненияПутейZIP.СохранятьОтносительныеПути,
   РежимОбработкиПодкаталоговZIP.ОбрабатыватьРекурсивно);
   Архив.Записать();
КонецПроцедуры

// Функция - Получить DOM-документ из XML-файла, возвращает XML-файл как DOM-модель
Функция ПолучитьDOMДокументИзXMLФайла(ПутьXMLФайла) Экспорт
   ЧтениеXML = Новый ЧтениеXML;
   ЧтениеXML.ОткрытьФайл(ПутьXMLФайла);
   ПостроительDOM = Новый ПостроительDOM;
   ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);
   ЧтениеXML.Закрыть();
   Возврат ДокументDOM;
КонецФункции

// Процедура - Сохранить DOM-документ как XML-файл, записывает DOM в указанный файл
Процедура СохранитьDOMДокументКАКXMLФайл(ДокументDOM, ПутьXMLФайла) Экспорт
   ЗаписьXML = Новый ЗаписьXML();
   ЗаписьXML.ОткрытьФайл(ПутьXMLФайла);
   ЗаписьDOM = Новый ЗаписьDOM();
   ЗаписьDOM.Записать(ДокументDOM, ЗаписьXML);
   ЗаписьXML.Закрыть();
КонецПроцедуры

// Точка входа - непосредственно на входе - имя файла, где необходимо вставить
// формулы
Процедура ЗаполнитьФормулыВФайлеXLSX(ПутьДоФайла) экспорт    
    ВременныйКаталог = КаталогВременныхФайлов() + "\excel_temp\";    
    СоздатьКаталог(ВременныйКаталог);    
    ИзвлечьАрхив(ПутьДоФайла, ВременныйКаталог);    
    ПутьДоXMLФайлаЛист1 = ВременныйКаталог + "xl\worksheets\sheet1.xml";
    // Чтение распакованного xml-файла листа 1 в ДокументDOM
    ДокументDOM = ПолучитьDOMДокументИзXMLФайла(ПутьДоXMLФайлаЛист1);
    СтроковыеЗначения = ПолучитьDOMДокументИзXMLФайла(ВременныйКаталог + "xl\sharedStrings.xml");    
    ВсеЯчейки = ДокументDOM.ПолучитьЭлементыПоИмени("c");
    ВсеСтроки = ДокументDOM.ПолучитьЭлементыПоИмени("row");
    ВсегоСтрок = ВсеСтроки.Количество();
    ВсеСтроковыеЗначения = СтроковыеЗначения.ЭлементДокумента.ДочерниеУзлы;    
    // Обход ячеек и определение формул по произвольному алгоритму
    Для Каждого Ячейка Из ВсеЯчейки Цикл        
        ИмяЯчейки = Ячейка.ПолучитьАтрибут("r");
        Если ИмяЯчейки = Неопределено Тогда Продолжить;КонецЕсли;        
        ИмяСтолбца = Сред(ИмяЯчейки, 1, 1);
        ИмяСтроки = Сред(ИмяЯчейки, 2);        
        НомерСтроки = Число(ИмяСтроки);    
        ТипЯчейки = Ячейка.ПолучитьАтрибут("t");
        Если ТипЯчейки="s" Тогда            
           Если Ячейка.ПервыйДочерний.ИмяУзла = "v" Тогда // здесь лежит какое-то значение  
           // надо найти значение в строках SharedStrings    
              ЗначениеЯчейки = ВсеСтроковыеЗначения[Число(Ячейка.ПервыйДочерний.ТекстовоеСодержимое)];                    
                    ЭтоФормула=СтрНачинаетсяС(ЗначениеЯчейки.ТекстовоеСодержимое,"="); //    Формула начинается с "="
                    Если ЭтоФормула Тогда 
                        формула=ЗначениеЯчейки.ТекстовоеСодержимое;
						формула=СтрЗаменить(формула,"=","");
                        Пока Ячейка.ЕстьДочерниеУзлы() Цикл
                            Ячейка.УдалитьДочерний(Ячейка.ПервыйДочерний);
                        КонецЦикла;                        
                        // Заполнение формулы
                        ЭлФормула = ДокументDOM.СоздатьЭлемент("f");
                        ЭлФормула.ТекстовоеСодержимое = Формула;                    
                        Ячейка.ДобавитьДочерний(ЭлФормула);
                    КонецЕсли;
           КонецЕсли;
        КонецЕсли;
    КонецЦикла;    
    // Запись модифицированного объекта ДокументDOM в xml-файл листа 1
    СохранитьDOMДокументКАКXMLФайл(ДокументDOM, ПутьДоXMLФайлаЛист1);    
    УдалитьФайлы(ПутьДоФайла);    
    СобратьАрхив(ВременныйКаталог, ПутьДоФайла);    
    УдалитьФайлы(ВременныйКаталог);    
КонецПроцедуры

Как использовать:

ТабДок=Новый ТабличныйДокумент;
Макет=ПолучитьОбщийМакет("ШаблонЛКУКЛС");
...
ОбластьТушка=Макет.ПолучитьОбласть("Тушка");
ОбластьТушка.Параметры.Разница="=G"+(ГСч+1)+"-H"+(ГСч+1); // = означает что тут формула в ячейке
ТабДок.Вывести(ОбластьТушка);					
...

ВрФайл=ПолучитьИмяВременногоФайла("xlsx");
ТабДок.Записать(ВрФайл,ТипФайлаТабличногоДокумента.XLSX);
						
СК_ГР_ФормулыВмакете.ЗаполнитьФормулыВФайлеXLSX(ВрФайл); // А теперь магия! Вставим формулу..

1С: Аутентификационный контекст клиента отсутствует в рабочем процессе

Данная ошибка возникла у меня, когда я в фоновом задании попытался вставить данные во внешнюю базу данных. Хотя если просто на сервере выполнять кусок когда вида:

	зап=внешниеисточникиданных.ОтчетыДля1С.Таблицы.reports_1c_public_raw_ias.СоздатьОбъект();	
	зап.communal="1"
    зап.Записать();	

То всё корректно отрабатывалось. Решением оказалось: перед любой операцией со внешним источником данных в фоновом задании проверять установлено ли соединение, и если нет — предварительно его устанавливать:

	состояние=ВнешниеИсточникиДанных.ОтчетыДля1С.ПолучитьСостояние();
	если состояние=СостояниеВнешнегоИсточникаДанных.Отключен тогда
		УстановитьПривилегированныйРежим(Истина);		
		Соединение = Новый ПараметрыСоединенияВнешнегоИсточникаДанных;    
		Соединение.АутентификацияОС=ложь;
		Соединение.АутентификацияСтандартная=ложь;
		Соединение.ИмяПользователя="укацукацу";
		Соединение.Пароль="цукаукацук";
		Соединение.СтрокаСоединения="DRIVER={PostgreSQL Unicode}; Data Source=PostgreSQL35W; SERVER=цукацука; PORT=5432; DATABASE=reports_1c; UID=цукацукацу; PWD=укацукацук";
		Соединение.СУБД="PostgreSQL";
		
		ВнешнийИсточник=ВнешниеИсточникиДанных.ОтчетыДля1С;
		ВнешнийИсточник.УстановитьОбщиеПараметрыСоединения(Соединение);
		ВнешнийИсточник.УстановитьПараметрыСоединенияПользователя(ПользователиИнформационнойБазы.ТекущийПользователь(),Соединение);	
		ВнешнийИсточник.УстановитьОбщиеПараметрыСоединения(Соединение);
		ВнешнийИсточник.УстановитьПараметрыСоединенияСеанса(Соединение);
		ВнешнийИсточник.УстановитьСоединение();
	
	конецесли;

1С: проверка почты по протоколу IMAP

Задача: прочитать почту из почтового ящика и обработать её посредством 1С.

Решение: за основу можно взять код что-то вроде:

Профиль = Новый ИнтернетПочтовыйПрофиль;
		Профиль.АутентификацияPOP3 = Ложь;
		Профиль.АутентификацияSMTP = Ложь;		
		// IMAP         		
	 УстановитьПривилегированныйРежим(Истина);
	  уз=справочники.УчетныеЗаписиЭлектроннойПочты.НайтиПоНаименованию("Поверка приборов учета");
      Пароли = ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища(уз, "Пароль, ПарольSMTP");
	УстановитьПривилегированныйРежим(Ложь);	  			
		Профиль.ИспользоватьSSLIMAP = Истина;
		Профиль.АдресСервераIMAP = уз.СерверВходящейПочты;
		Профиль.ПортIMAP = уз.ПортСервераВходящейПочты; 	
		Профиль.ПользовательIMAP = уз.ПользовательSMTP;
		Профиль.ПарольIMAP = Пароли.ПарольSMTP;
		Профиль.ТолькоЗащищеннаяАутентификацияIMAP=Ложь;
		IПочта = Новый ИнтернетПочта;
		Сообщ = Новый СообщениеПользователю();
			IПочта.Подключиться(Профиль, ПротоколИнтернетПочты.IMAP); //ПротоколИнтернетПочты.POP3		
			заголовки=IПочта.ПолучитьЗаголовки();
			если заголовки.Количество()>0 тогда		
				ПоследнийЗаголовок=Новый Массив();
				ПоследнийЗаголовок.Добавить(заголовки[заголовки.Количество()-1]);					
				МассивСообщений = Новый Массив;
				МассивСообщений = IПочта.Выбрать(Ложь,ПоследнийЗаголовок);					
				ТекстСообщения=МассивСообщений[0].тексты[0].Текст;			
					уд=Новый Массив();
					уд.Добавить(МассивСообщений[0]);
					IПочта.УдалитьСообщения(уд);	
					IПочта.ОчиститьУдаленныеСообщения();
			иначе	
				answer.result="писем нет";
			конецесли;		
		IПочта.Отключиться(); 	

1С: таблица значений на форме

Задача: скрыть отдельную колонку или показать все колонки в таблице значений расположенной на форме.

Решение: напишем две процедуры, одна из которых скрывает текущую выбранную мышкой колонку, а другая показывает все колонки в выбранной таблице.

&НаКлиенте
Процедура СкрытьКолонку(Команда)
      ТЭ_имя_объект=ТекущийЭлемент.Имя;
      ТЭ_поле=ТекущийЭлемент.ТекущийЭлемент.имя;
      имяКолонки=СтрЗаменить( ТЭ_поле,ТЭ_имя_объект,"");	  
	  элементы[ТЭ_поле].Видимость=Ложь;
КонецПроцедуры

&НаКлиенте
Процедура ПоказатьВсеКолонки(Команда)
      ТЭ_имя_объект=ТекущийЭлемент.Имя;
      ТЭ_поле=ТекущийЭлемент.ТекущийЭлемент.имя;
      имяКолонки=СтрЗаменить( ТЭ_поле,ТЭ_имя_объект,"");
	  для каждого стр из элементы[ТЭ_имя_объект].ПодчиненныеЭлементы цикл
		  стр.Видимость=Истина;
	  конеццикла;	  
КонецПроцедуры

Функционал можно например навесить на контекстное меню

1С: Сжимаем прикрепленные файлы

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

Решение:

	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ ПЕРВЫЕ 1000
		|	Файлы.ВладелецФайла КАК ВладелецФайла,
		|	Файлы.Ссылка КАК Ссылка,
		|	Файлы.ПолноеНаименование КАК ПолноеНаименование,
		|	Файлы.ТекущаяВерсияПутьКФайлу КАК ПутьКФайлу,
		|	Файлы.ТекущаяВерсияТом.ПолныйПутьWindows КАК ПолныйПуть,
		|	Файлы.ДатаСоздания КАК ДатаСоздания
		|ИЗ
		|	Справочник.Файлы КАК Файлы
		|ГДЕ
		|	Файлы.ВладелецФайла ССЫЛКА Справочник.СК_ГосуслугиЛК_ВходящиеСообщения
		|	И Файлы.ПометкаУдаления = ЛОЖЬ
		|	И НЕ Файлы.ТекущаяВерсияПутьКФайлу ПОДОБНО ""%zip%""
		|	И Файлы.ДатаСоздания МЕЖДУ &ДатаС И &ДатаПо
		|
		|УПОРЯДОЧИТЬ ПО
		|	ДатаСоздания";	
	Запрос.УстановитьПараметр("ДатаС", объект.ДатаС);	
	Запрос.УстановитьПараметр("ДатаПо", объект.ДатаПо);	
	РезультатЗапроса = Запрос.Выполнить();	
	ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();	
	Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
		если СтрНайти(ВыборкаДетальныеЗаписи.ПутьКФайлу,".zip")=0 тогда
			НовыйАрхив = Новый ЗаписьZipФайла(
			        ВыборкаДетальныеЗаписи.ПолныйПуть+"tmp.zip",
			        "","",МетодСжатияZIP.Сжатие,УровеньСжатияZIP.Максимальный,МетодШифрованияZIP.Zip20					
			);			
			НовыйАрхив.Добавить(ВыборкаДетальныеЗаписи.ПолныйПуть+ВыборкаДетальныеЗаписи.ПутьКФайлу);
			НовыйАрхив.Записать();            
			//возврат 0;
			ДвоичныеДанные = Новый ДвоичныеДанные(ВыборкаДетальныеЗаписи.ПолныйПуть+"tmp.zip"); 
			АдресФайлаВХранилище = ПоместитьВоВременноеХранилище(ДвоичныеДанные);
			РаботаСФайламиВызовСервера.СоздатьФайлСВерсией(
				ВыборкаДетальныеЗаписи.ВладелецФайла,
				ВыборкаДетальныеЗаписи.ПолноеНаименование+".zip",
				"zip",
				ТекущаяДата(),
				ТекущаяДата(),
				,
				АдресФайлаВХранилище,АдресФайлаВХранилище,
				Ложь,
				,
				,
				Истина
			);						
			об=ВыборкаДетальныеЗаписи.Ссылка.ПолучитьОбъект();
			об.ПометкаУдаления=Истина;
			об.Записать();
			об.Удалить();					
			УдалитьФайлы(ВыборкаДетальныеЗаписи.ПолныйПуть+ВыборкаДетальныеЗаписи.ПутьКФайлу);						
		конецесли;		
	КонецЦикла;

Т.е. что тут делаем: выбираем элемент справочника с прикрепленным файлом, сжимаем его в архив zip, прикрепляем его и удаляем оригинал.

1 2 3 37