Чтение файлов Excel при помощи ADO

При больших файлах Excel чтение каждой ячейки через COM объект Excel.Application приводит к большим затратам времени, для ускорения процесса чтения можно воспользоваться объектом ADODB. Обработка происходит на клиенте, поэтому файл Excel читается в массив строк, где строка представлена как массив.

&НаКлиенте
Функция ПолучитьМассивXLSФайла(ИмяФайлаЗагрузки)

Connection = Новый COMОбъект(«ADODB.Connection»);
// Можно использовать строку подключения для Excel ранее 2007
//СтрокаПодключения = «Provider=Microsoft.Jet.OLEDB.4.0; Data Source = » + ИмяФайлаЗагрузки;
СтрокаПодключения = «Provider=Microsoft.ACE.OLEDB.12.0; Data Source = « + ИмяФайлаЗагрузки;
СтрокаПодключения = СтрокаПодключения+«; Extended Properties = «+«»»Excel 8.0″+»;HDR=NO;IMEX=1″»;»;

Попытка
   Connection.Open(СтрокаПодключения);
Исключение
   Сообщить(ОписаниеОшибки());
   Возврат Неопределено;
КонецПопытки;

Command = Новый COMОбъект(«ADODB.Command»);
axCatalog = Новый COMОбъект(«ADOX.Catalog»);
axCatalog.ActiveConnection = Connection;
// получить имя первого листа
Для каждого Лист ИЗ axCatalog.Tables Цикл
      ИмяТаблицы = Лист.Name;
      Прервать;
КонецЦикла;

RecordSet = Новый COMОбъект(«ADODB.RecordSet»);
Command.ActiveConnection = Connection;
Command.CommandText =«SELECT COUNT(*) FROM [«+ИмяТаблицы+«]»;
Command.CommandType =1;
RecordSet = Command.Execute();
КоличествоСтрок = RecordSet.Fields(0).Value;
Command.CommandText = «SELECT * FROM [«+ИмяТаблицы+«]»;
Command.CommandType = 1;
Попытка
      RecordSet = Command.Execute();
Исключение
      Сообщить(ОписаниеОшибки());
КонецПопытки;

RecordSet.MoveNext();
ФайлВФормеМассива = новый Массив;

Пока RecordSet.EOF() = 0 Цикл
   МассивСтроки = новый Массив;
   для НомерПоля = 1 по RecordSet.Fields.Count цикл
      МассивСтроки.Добавить(RecordSet.Fields(НомерПоля1).Value);
   КонецЦикла;
   ФайлВФормеМассива.Добавить(МассивСтроки);
   RecordSet.MoveNext();
КонецЦикла;
RecordSet.Close();
Connection.Close();

Возврат ФайлВФормеМассива;

КонецФункции

Если названия листов на русском языке, то после имени листа надо ставить знак «$».

Как получить макет отчета в управляемой форме

Функция ПолучитьМакетНаСервере()

ОбъектОтчета = РеквизитФормыВЗначение(«Отчет»);
Макет = ОбъектОтчета.ПолучитьМакет(«Макет»);
Возврат Макет;

КонецФункции

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

Программное изменение внешнего вида табличного документа позволяет изменить границу ячейки или области (на примере — пунктирная граница):

ГраницаПунктир = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.РедкийПунктир,1);

ОбластьМакета = Макет.ПолучитьОбласть(«СтрокаТаблицы»);

ОбластьМакета.Область(«R1C4:R1C7»).ГраницаСнизу = ГраницаПунктир;
ОбластьМакета.Область(«R2C4:R2C7»).ГраницаСверху = ГраницаПунктир;
ОбластьМакета.Область(«R1C4:R1C7»).ГраницаСлева = ГраницаПунктир;
ОбластьМакета.Область(«R1C4:R1C7»).ГраницаСправа = ГраницаПунктир;

Так же можно программно объединять ячейки в табличном документе:

ТабДок.Область(«R1C1:R1C4»).Объединить();

Удаление дублей иерархии при получении результата запроса

При использовании запросов с оператором ИЕРАРХИЯ и последующей выгрузке в дерево есть проблема, с которой знакомы большинство программистов — наличие дублей в иерархии, на справочника номенклатуры:

Запрос и результат:

request

Чтобы убрать дубли после получения дерева значений из результата запроса можно воспользоваться функциями ниже. Поле ключа — поле иерархии (Номенклатура).

Функция УдалитьДублирующиесяУзлыДерева(Дерево, _ПоляКлюча) Экспорт

ПоляКлюча = СтрРазделить(_ПоляКлюча, «,»);
Дерево2 = новый ДеревоЗначений;
для каждого колонка из Дерево.Колонки цикл
Дерево2.Колонки.Добавить(колонка.Имя, колонка.ТипЗначения);
КонецЦикла;
для каждого СтрКорня из Дерево.Строки цикл
НС = Дерево2.Строки.Добавить();
ЗаполнитьЗначенияСвойств(НС, СтрКорня);
СкопироватьРекурсивно(НС, СтрКорня, ПоляКлюча);
КонецЦикла;

Возврат Дерево2;

КонецФункции

Процедура СкопироватьРекурсивно(СтрокаКопия, СтрДерева, ПоляКлюча)

для каждого СтрПотомка из СтрДерева.Строки цикл
ЕстьРазличия = ложь;
для каждого ПолеКлюча из ПоляКлюча цикл
Если СтрПотомка[ПолеКлюча] <> СтрДерева[ПолеКлюча] тогда
ЕстьРазличия = истина;
Прервать;
КонецЕсли;
КонецЦикла;
Если ЕстьРазличия тогда
НС = СтрокаКопия.Строки.Добавить();
ЗаполнитьЗначенияСвойств(НС, СтрПотомка);
СкопироватьРекурсивно(НС, СтрПотомка, ПоляКлюча);
Иначе
СкопироватьРекурсивно(СтрокаКопия, СтрПотомка, ПоляКлюча);
КонецЕсли;
КонецЦикла;

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

Печать на принтере документов Word и Excel из 1Сv8.3

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

&НаКлиенте
Процедура ПечатьDOCФайлов(ПутьКФайлу, ИмяПринтера = «»
WordAppl = Новый COMОбъект(«Word.Application»);
WordAppl.Documents.Open(ПутьКФайлу);
WordAppl.Documents(ПутьКФайлу).Activate();
WordAppl.ActivePrinter = ИмяПринтера;
WordAppl.ActiveDocument.PrintOut();
WordAppl.ActiveDocument.close();
КонецПроцедуры

&НаКлиенте
Процедура ПечатьExcelФайлов(ПутьКФайлу, ИмяПринтера = «»)
ExcelAppl = Новый COMОбъект(«Excel.Application»);
ExcelAppl.Workbooks.Open(ПутьКФайлу);
ExcelAppl.ActiveSheet.PrintOut(,,,,ИмяПринтера);
ExcelAppl.WorkBooks.Close();
ExcelAppl.Quit();
КонецПроцедуры

Полезные функции

Выделяет из строки числовые символы и возвращает число
Функция ОставитьЧисловыеСимволыВСтроке(СтрокаСЧислом, ВернутьЧисло=истина)

ДлинаСтроки = СтрДлина(СтрокаСЧислом);
СтрокаФинал = «»;
для й=1 по ДлинаСтроки цикл
ТекСимвол = Сред(СтрокаСЧислом,й,1);
Если ТекСимвол >= «0» и ТекСимвол <= «9» тогда
СтрокаФинал = СтрокаФинал + ТекСимвол;
КонецЕсли;
КонецЦикла;
Возврат ?(ВернутьЧисло, Число(СтрокаФинал), СтрокаФинал);
КонецФункции

Получение описания типа (для динамического добавления колонки в таблицу значений)
Функция ПолучитьОписаниеЦелочисленногоТипа() Экспорт

КЧ = Новый КвалификаторыЧисла(10);
Массив = Новый Массив;
Массив.Добавить(Тип(«Число»));
Возврат Новый ОписаниеТипов(Массив, , ,КЧ);
КонецФункции

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

Функция для получения описания типов строки, заданной длины
Функция ПолучитьОписаниеТиповСтроки(ДлинаСтроки
Массив = Новый Массив;
Массив.Добавить(Тип(«Строка»));
КвалификаторСтроки = Новый КвалификаторыСтроки(ДлинаСтроки, ДопустимаяДлина.Переменная);
Возврат Новый ОписаниеТипов(Массив, , КвалификаторСтроки);
КонецФункции

Функция для получения описания типов числа, заданной разрядности
Функция ПолучитьОписаниеТиповЧисла(Разрядность,РазрядностьДробнойЧасти=0
Массив = Новый Массив;
Массив.Добавить(Тип(«Число»));
КвалификаторЧисла = Новый КвалификаторыЧисла(Разрядность,РазрядностьДробнойЧасти);
Возврат Новый ОписаниеТипов(Массив, КвалификаторЧисла);
КонецФункции

Функция для получения описания типов даты
Функция ПолучитьОписаниеТиповДаты(ЧастиДаты
Массив = Новый Массив;
Массив.Добавить(Тип(«Дата»));
КвалификаторДаты = Новый КвалификаторыДаты(ЧастиДаты);
Возврат Новый ОписаниеТипов(Массив, , , КвалификаторДаты);
КонецФункции

Создание дерева в СКД и выгрузка его в дерево значений

Допустим, имеется таблица с товарами и суммами, колонки приведены ниже:
— Идентификатор строки (id)
— Идентификатор строки родителя (idParent)
— Наименование (строка)
— Сумма

id idParent Наименование Сумма (руб.)
1 Монитор 5000
2 Мышь, клавиатура 2000
3 Системный блок
4 3 Материнская плата 10000
5 3 Жесткий диск 3000

Колонка «Наименование» не является справочником и не позволяет автоматически создать иерархию, конечно ее можно создать программно, но это трудоемко, особенно собирать суммы итогов по иерархии. Итак, нам нужно получить дерево значений без особо трудного кодирования. Для начала, создадим СКД и создадим 2 частично одинаковых выборки с данными, как показано на рисунках ниже:

Первая выборка, задающая иерархию

SetIerarh

Вторая выборка, такая же как первая, но содержит больше колонок

SetData

Связи между выборками, образующих дерево

svyaz

Структура итоговых данных — само дерево

report

Если посмотреть на результат в отчете, он будет выглядеть так

result

Ниже приведен код, позволяющий получить дерево из СКД в переменную «ДеревоЗначений»:

СхемаКомпоновкиДанных = РеквизитФормыВЗначение(«Отчет»).ПолучитьМакет(«МакетДанные»);
КомпоновщикНастроек = Новый КомпоновщикНастроекКомпоновкиДанных;
КомпоновщикНастроек.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(СхемаКомпоновкиДанных));
КомпоновщикНастроек.ЗагрузитьНастройки(СхемаКомпоновкиДанных.НастройкиПоУмолчанию);

НастройкиКомпоновщика = КомпоновщикНастроек.Настройки;
ПараметрыНастройки = НастройкиКомпоновщика.ПараметрыДанных;

// если нужны параметры — устанавливаем так
Параметр = ПараметрыНастройки.Элементы.Найти(«Дата»);
Параметр.Использование = Истина;
Параметр.Значение = Отчет.Дата;

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

Как изменить представление документа в 1С v 8.3

Допустим для документа Реализация товаров услуг нужно настроить представление в виде «Реализация т/у № 150 от 20.05.2016 (Контрагент: ООО Альфа)». Для этого в модуле менеджера объекта документа создаем обработчики событий получения представления и полей представления:

Процедура ОбработкаПолученияПредставления(Данные, Представление, СтандартнаяОбработка)
Представление = «Реализация т/у № « + Данные.Номер + » от « + Формат(Данные.Дата,«ДФ=dd.MM.yyyy») + » (Контрагент: «+Строка(Данные.Контрагент)+«)»;
СтандартнаяОбработка=Ложь;
КонецПроцедуры

Процедура ОбработкаПолученияПолейПредставления(Поля, СтандартнаяОбработка)
Поля.Добавить(«Номер»);
Поля.Добавить(«Дата»);
Поля.Добавить(«Контрагент»);
СтандартнаяОбработка=Ложь;
КонецПроцедуры

Где хранится список информационных баз 1С 8.x

При переносе данных с одного компьютера на другой иногда необходимо без запуска 1С узнать список баз, которые отображаются при запуске 1С. Список баз хранится в обычном текстовом файле ibases.v8i. Для каждого пользователя 1С создает свой файл, поэтому необходимо знать имя пользователя, пусть это будет MyUser, пути к файлу указаны ниже:

bases

Версия 1С 8.1

Win XP:
C:\Documents and Settings\MyUser\Application Data\1C\1Cv81\ibases.v8i

Vista, 7, 8:
C:\Users\MyUser\AppData\Roaming\1C\1Cv81t\ibases.v8i

Версия 1С 8.2, 8.3

Win XP:
C:\Documents and Settings\MyUser\Application Data\1C\1CEStart\ibases.v8i

Vista, 7, 8:
C:\Users\MyUser\AppData\Roaming\1C\1CEStart\ibases.v8i

Проверка принадлежности элемента иерархии

Проверять принадлежность элемента справочника вышестоящему элементу или группе можно двумя способами:
1. Запросом
2. Программно

Допустим надо проверить принадлежность некоторого элемента ПодчиненныйКонтрагент справочника Контрагенты элементу ГлавныйКонтрагент этого же справочника.

Запросом

Наличие хотя бы одной записи в запросе говорит о том, что элемент ПодчиненныйКонтрагент подчинен элементу или группе ГлавныйКонтрагент:

Запрос = новый Запрос(«Выбрать
|Контрагенты.Ссылка
|    из
|Справочник.Контрагенты как Контрагенты
|    где
|Контрагенты.Ссылка в Иерархи(&ГлавныйКонтрагент) и Контрагенты.Ссылка |= &ПодчиненныйКонтрагент»);

Запрос.УстановитьПараметр(«ГлавныйКонтрагент», ГлавныйКонтрагент);
Запрос.УстановитьПараметр(«ПодчиненныйКонтрагент»ПодчиненныйКонтрагент);
Если Запрос.Выполнить().Выбрать().Следующий() тогда
    Сообщить(«Элемент подчинен»);
Иначе
    Сообщить(«Элемент НЕ подчинен»);
КонецЕсли;

Программно

Легче данную операцию сделать программно, для этого используется процедура ПринадлежитЭлементу элемента справочника:

Если ПодчиненныйКонтрагент.ПринадлежитЭлементу(ГлавныйКонтрагент) тогда
    Сообщить(«Элемент подчинен»);
Иначе
    Сообщить(«Элемент НЕ подчинен»);
КонецЕсли;

Примечание:
Выражение ГлавныйКонтрагент.ПринадлежитЭлементу(ГлавныйКонтрагент) вернет ЛОЖЬ.