Столкнулся очередной раз с задачей древней как мир, кому-то из коллег показалось что в excel задача по загрузке информации в регистр сведений 1С (в частности ЛицевыеСчетаСотрудников) будет выполняться проще, чем в интерфейсе 1С. Но не надо на этом зацикливаться, информация, изложенная ниже, носит более широкий характер. Так вот, ввиду отсутствия MS Office на компьютере с базой пользователь благополучно был с обидой отправлен восвояси, при этом на локальном компьютере у пользователя был установлен офис, и это даже ставилось как аргумент. Позже возникла необходимость загрузки информации в похожий регистр, но задача отличалась тем, что теперь требовалось загрузить из Excel с локальной тачки в клиент-серверную базу. Устав людям доказывать, что не одним экселем сыт 1С, взялся за реализацию несложной задачи и так получилось, что увидел в наискучнейшем рутинном занятии повод для изысканий тут. Итак, как ни странно, подробного разбора полетов не нашел ни здесь, ни на профильных сайтах, есть опытные ответчики на сайтах и тут тоже был замечен из категории черного пояса по "Спасибо, кэп", с советами "в управляемом приложении перенеси все &НаКлиент" или "Конечно, перед открытием нужно указать путь на сервере, проснулся, типа скачай мою обработку и научись". Так вот эта заметка будет полезна тем, кто обойдется без выслушивания подобного рода высказывателей.
Со времен Толстого, задача действительно разделилась. И у банальной процедуры загрузки появились варианты, где ее выполнять, на клиенте или на сервере.
Первый вариант &НаКлиенте
Подходит для озвученной мною задачи, если у вас файл Эксель это просто несколько колонок с загружаемыми реквизитами, простой структуры, типа колонка - снизу ее значение и никаких логических или сложных арифметических действий или индексирования со значениями в колонках не требуется, тогда будет достаточно следующего кода. Замечу, этот код не зависит от типа базы, файлоая/серверная и требуется наличие экселя только на стороне клиента (это из области "Спасибо, кэп", но будет полезно в определении круга задач для тех, кто читал с начала)
&НаКлиенте
Процедура Загрузка(Команда)
Колонки = Новый Массив;
Колонки.Добавить("Сотрудник");
Колонки.Добавить("Счет");
Попытка
ex = ПолучитьCOMобъект("","Excel.Application");
Исключение
Сообщить("Excel Application не создан!!");
Возврат;
КонецПопытки;
Попытка
ex.workbooks.open(Файл,1);
Исключение
Сообщить("Файл перемещен или удален!");
Возврат;
КонецПопытки;
RCount = ex.ActiveSheet.UsedRange.Rows.Count();
Для j = 2 по RCount цикл
Если СокрЛП(ex.ActiveSheet.Cells(j,1).Value)="" Тогда
Продолжить;
КонецЕсли;
Стр = Новый Массив;
Для i=1 По Колонки.Количество() Цикл
Стр.Добавить(СокрЛП(ex.ActiveSheet.Cells(j,i).Value));
КонецЦикла;
ДобавитьЗаписьЛицевойСчет(Стр, ВыбПроект);
КонецЦикла;
ex.workbooks.Close();
ex.quit();
КонецПроцедуры
Второй вариант &НаСервере.
После загрузки вам необходимо выполнить группировку загруженных данных, например, вы загружаете информацию не по лицевым счетам, а по загрузке графиков работы сотрудников при суммированном учете, не спорю, можно это извернуться и сделать массивами &НаКлиенте, но при загрузке большого объема данных логичнее в целях увеличения производительности перенести операцию &НаСервер и выполнить загрузку в таблицу значений. При явном указании пути к файлу на клиенте в процедуру &НаСервере, в лучшем случае получите сообщение, что файл не найден. Поэтому перед выполнением необходимо скопировать файл во временное хранилище в процедуре &НаКлиенте, а затем сохранить его во временный каталог уже на сервере
&НаКлиенте
Процедура Загрузка(Команда)
Двоичное = Новый ДвоичныеДанные(Файл);
Адрес = ПоместитьВоВременноеХранилище(Двоичное, ЭтаФорма.УникальныйИдентификатор);
ЗагрузкаНаСервере(Адрес, ВыбПроект);
КонецПроцедуры
&НаСервере
Процедура ЗагрузкаНаСервере(Адрес, Проект)
темп_Путь = КаталогВременныхФайлов()+ "prncss_Megan_"+Формат(ТекущаяДата()-Дата(2012,01,01), "ЧГ=0")+".xls";
темп_файл = ПолучитьИзВременногоХранилища(Адрес);
темп_файл.Записать(темп_Путь);
СписокКолонок = Новый СписокЗначений;
СписокКолонок.Добавить("ФизЛицо");
СписокКолонок.Добавить("НомерЛицевогоСчета");
ТабЛицСчетов = ЗагрузитьЭксель(темп_Путь,СписокКолонок);
Попытка
УдалитьФайлы(темп_Путь);
Исключение
Сообщить(ОписаниеОшибки());
КонецПопытки;
....
КонецПроцедуры
&НаСервере
Функция ЗагрузитьЭксель(Путь, СписокКолонки)
ТЗФайл = Новый ТаблицаЗначений;
Попытка
ex = ПолучитьCOMобъект("","Excel.Application");
Исключение
Сообщить("Excel Application не создан!!");
Возврат ТЗФайл;
КонецПопытки;
Попытка
ex.workbooks.open(Путь,1);
Исключение
Сообщить("Файл перемещен или удален!");
Возврат ТЗФайл;
КонецПопытки;
Для каждого Зн Из СписокКолонки Цикл
ТЗФайл.Колонки.Добавить(Зн.Значение);
КонецЦикла;
RCount = ex.ActiveSheet.UsedRange.Rows.Count();
CCount = ex.ActiveSheet.UsedRange.Columns.Count();
Для j = 2 по RCount цикл
Новая = ТЗФайл.Добавить();
Для i=1 По СписокКолонки.Количество() Цикл
Новая.Установить(i-1, СокрЛП(ex.ActiveSheet.Cells(j,i).Value));
КонецЦикла;
КонецЦикла;
ex.workbooks.Close();
ex.quit();
Возврат ТЗФайл;
КонецФункции
Временный каталог используется стандартного пользователя USR1CV82. В своем коде я еще применил таймстэмп на всякий случай, во избежание ошибки разделенного доступа к файлу в случае неожиданного завершения в прошлый запуск (почему-то окончание фразы сразу подумалось о другом и стало немного грустно ;) а потом весело: не только 1С-ники косячат).
Всем благ, поменьше вам гневных советчиков на форумах, те, кто ничего нового не прочел, но упорно читал до конца, отвечу вам фразой известного футболиста про "Ваши ожидания".