Проверка данных Exel на клиенте

1. SantiouS 17.08.20 10:58 Сейчас в теме
Цель: есть документ "Заказ" с табличной частью "Товары" и колонками "Номенклатура" и "Количество". Этот документ заполнен рядом номенклатур и количеств. Далее от клиента попадает документ Exel с номенклатурами и количеством и нужно реализовать механизм, который найдёт соответствие номенклатуры с документа "Заказ" и файла Exel, после чего изменит значение количества в заказе.
В кратце, с файла нужно обновить данные в заказе.
Для этого я сделал так как показано ниже в коде, но мне все же интересно. Можно было как то реализовать проверку файла не скидывая его на сервер, то есть сразу на клиенте?
Так же в коде есть комментарии с моими страданиями, а именно попытки использовать процедуру "НачатьПомещениеФайлаНаСервер", которая, как оказалось, не поддерживается на моей платформе, а так же попытка чтения через потоки, который, как снова оказалось, не умеют работать с форматом файла xlsx.
&НаКлиенте
Процедура ОбновитьСФайла(Команда)
	ДиалогВыбораФайлаЗаказа=Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
	ДиалогВыбораФайлаЗаказа.Заголовок="Выбор файла";
	ДиалогВыбораФайлаЗаказа.МножественныйВыбор =  Ложь;
	ДиалогВыбораФайлаЗаказа.Фильтр="Файл Exel(*.xlsx)|*.xlsx";
	ДиалогВыбораФайлаЗаказа.ПредварительныйПросмотр=Истина;
	ДиалогВыбораФайлаЗаказа.Показать(Новый ОписаниеОповещения("РезультатВыбораФайла",ЭтаФорма));	
КонецПроцедуры

&НаКлиенте
Процедура РезультатВыбораФайла(ВыбраныеФайлы,ДополнительныеПараметры) Экспорт
	Если НЕ ЗначениеЗаполнено(ВыбраныеФайлы) Тогда
		Возврат;	
	КонецЕсли; 
	//НачатьПомещениеФайлаНаСервер(Новый ОписаниеОповещения("РезультатПерегрузкиФайлаНаСервер",ЭтаФорма),,,,ВыбраныеФайлы[0],УникальныйИдентификатор);
	Файл = Новый ДвоичныеДанные(ВыбраныеФайлы[0]);
	Адрес = ПоместитьВоВременноеХранилище(Файл, ЭтаФорма.УникальныйИдентификатор);
	ОбработкаНаСервере(Адрес);	
КонецПроцедуры



&НаСервере
Процедура ОбработкаНаСервере(Адрес=Неопределено) 
	Если НЕ ЗначениеЗаполнено(Адрес) Тогда
		Возврат;
	КонецЕсли;  
	
	ИмяВременногоФайла=ПолучитьИмяВременногоФайла(".xlsx");
	ДвоичныеДанные = ПолучитьИзВременногоХранилища(Адрес);
	ДвоичныеДанные.Записать(ИмяВременногоФайла);
	ТабДокумент=Новый ТабличныйДокумент;
	ТабДокумент.Прочитать(ИмяВременногоФайла, СпособЧтенияЗначенийТабличногоДокумента.Текст);
	
	//невозможно реализовать через потоки из за отсутствия поддержки обработки документов формата xlsx
	//ПотокДляЧтения=ДвоичныеДанные.ОткрытьПотокДляЧтения();
	//ПотокДляЧтения.Перейти(0, ПозицияВПотоке.Начало);
	//ТабДокумент=Новый ТабличныйДокумент;
	//ТабДокумент.Прочитать(ПотокДляЧтения, СпособЧтенияЗначенийТабличногоДокумента.Текст);
	//ПотокДляЧтения.Закрыть();	
	
	СтолбецИтога=16;
	//R - строка, C - колонка
	//обход документа
	Для СтрокаНомер=4 По 500 Цикл 
		НоменклатураТабДок=ТабДокумент.Область("R"+Строка(СтрокаНомер)+"C1").Текст;				
		ГотовитьсяКОтправке=ТабДокумент.Область("R"+Строка(СтрокаНомер)+"C"+Строка(СтолбецИтога)).Текст;
		Если ЗначениеЗаполнено(НоменклатураТабДок) И ЗначениеЗаполнено(ГотовитьсяКОтправке) Тогда
			Попытка
				ГотовитьсяКОтправке=Число(ГотовитьсяКОтправке);
			Исключение
				Сообщить("Не удалось распорзанать итоговое количество для номенклатры "+НоменклатураТабДок+". Операция завершилась наудачей!");
				Возврат;
			КонецПопытки; 
			//поиск строки для замены итогового количества
			Для каждого СтрокаТовары Из Объект.ТоварыЗаказ Цикл
				Если СтрокаТовары.Номенклатура.Наименование=НоменклатураТабДок Тогда
					СтрокаТовары.РезультатРеальный=ГотовитьсяКОтправке;	
				КонецЕсли; 
			КонецЦикла; 	
		Иначе
			Прервать;
		КонецЕсли;
	КонецЦикла;	       
	//очистка от файла
	Попытка
        УдалитьФайлы(ИмяВременногоФайла);
    Исключение
        Сообщить("Возникли проблемы с удалением временного файла");
		Возврат;
    КонецПопытки;
КонецПроцедуры;  
Показать
По теме из базы знаний
Ответы
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
4. DJDUH 17 17.08.20 11:35 Сейчас в теме
(1) А открыть ТабДоком - не пробовали?
5. SantiouS 17.08.20 11:35 Сейчас в теме
(4) Метод "Прочитать" работает только на сервере. На ТК не работает.
2. Vitaly1C8 17.08.20 11:24 Сейчас в теме
Можно на клиенте. См пример


&НаКлиенте
Процедура ЗагрузитьИзXLS(Команда)	
	// ПолноеИмяФайлаШаблона = КаталогДокументов() + "ОценочнаяСводный.xlsx";
	ПолноеИмяФайлаШаблона = Объект.ИмяЭксельФайла;
	Файл = Новый Файл(ПолноеИмяФайлаШаблона);
	Если НЕ Файл.Существует() Тогда
		Сообщить("Файл шаблона (отсутствует) " + ПолноеИмяФайлаШаблона);
	Иначе
		//ПолноеИмяФайлаЭкспорт = КаталогДокументов() + СокрЛП(Объект.Сотрудник) + ".xlsx";
		//КопироватьФайл(ПолноеИмяФайлаШаблона, ПолноеИмяФайлаЭкспорт);
		//Сообщить("Создаем файл " + ПолноеИмяФайлаЭкспорт);
		//ВыгрузитьВЭксельФайл(ПолноеИмяФайлаЭкспорт);
		Если ЗагрузитьИзЭкселя(ПолноеИмяФайлаШаблона) Тогда
			Сообщить("Данные загружены из " + ПолноеИмяФайлаШаблона);
		КонецЕсли;
		
	КонецЕсли;
КонецПроцедуры

&НаКлиенте
Функция ЗагрузитьИзЭкселя(ИмяФайла)
	// Вставить содержимое обработчика.
	Попытка
        Excel = новый COMОбъект("Excel.Application");
    Исключение
        Сообщить("Похоже, Excel на компьютере не установлен. Необходимо выполнить установку/переустановку Excel.");
        Возврат Ложь;
    КонецПопытки;     
	
	// Подключились успешно, открываем файл	(только для чтения)
    Excel.Workbooks.Open(ИмяФайла,,Истина);	
    
	//Номер листа в книге Excel для получения данных
    // НомерЛиста = 1;
	//Открываем необходимый лист
    Sheet = Excel.Sheets("Лист1");
	Sheet.Select();	
	
	НачСтрока = 0; НачКолонка = 0; КонСтрока = 0;
	Если ПолучитьRowColДиапазона(Sheet, "Блок", НачСтрока, НачКолонка, КонСтрока, "$L$5:$P$8") Тогда	
		тчБлок = Объект.Блок;
		тчБлок.Очистить();		
		// Блок :: F4 - J7
		Для б=НачСтрока по КонСтрока Цикл
			стр = тчБлок.Добавить();
			стр.ФункБлок = Excel.Cells(б, НачКолонка).Value;	// F
			стр.Выручка = Excel.Cells(б, НачКолонка+1).Value;	// G
			стр.OIBDA = Excel.Cells(б, НачКолонка+2).Value;		// H
			стр.Roll_out = Excel.Cells(б, НачКолонка+3).Value;	// I
		КонецЦикла;	
	Иначе
		Сообщить("Функциональный блок - не загружен");
	КонецЕсли;	
	
	НачСтрока = 0; НачКолонка = 0; КонСтрока = 0;
	Если ПолучитьRowColДиапазона(Sheet, "весгод", НачСтрока, НачКолонка, КонСтрока, "$F$15:$H$24") Тогда	
		тчВесгод = Объект.Весгод;
		тчВесгод.Очистить();		
		// Весгод F15 (6) : H24 (8)
		Для б=НачСтрока по КонСтрока Цикл
			стр = тчВесгод.Добавить();
			стр.Грейд = Excel.Cells(б, НачКолонка).Value;					// F
			стр.БизнесПоказатели = Excel.Cells(б, НачКолонка + 1).Value;	// G
			стр.ИндЗадачи = Excel.Cells(б, НачКолонка + 2).Value;			// H
		КонецЦикла;
	Иначе
		Сообщить("Вес показателей - не загружен");
	КонецЕсли;	
	
	НачСтрока = 0; НачКолонка = 0; КонСтрока = 0;
	Если ПолучитьRowColДиапазона(Sheet, "грейд", НачСтрока, НачКолонка, КонСтрока, "$A$3:$C$12") Тогда
		тчГрейд = Объект.Грейд;
		тчГрейд.Очистить();		
		// Грейд A3 : C12 (3)
		Для б=НачСтрока по КонСтрока Цикл
			стр = тчГрейд.Добавить();
			стр.Грейд = Excel.Cells(б, НачКолонка).Value;		    // A
			стр.Полугодовая = Excel.Cells(б, НачКолонка + 1).Value;	// B
			стр.Годовая = Excel.Cells(б, НачКолонка + 2).Value;     // C
			стр.ИтогоПремиальныйФонд = стр.Полугодовая + стр.Годовая;
		КонецЦикла;
	Иначе
		Сообщить("Грейд - не загружен");
	КонецЕсли;
	
	НачСтрока = 0; НачКолонка = 0; КонСтрока = 0;
	Если ПолучитьRowColДиапазона(Sheet, "бизнес", НачСтрока, НачКолонка, КонСтрока, "$F$10:$K$12") Тогда
		тчБизнес = Объект.БизнесПоказатели;
		тчБизнес.Очистить();
		// бизнес F10 : K12 
		Для б=НачСтрока по КонСтрока Цикл
			стр = тчБизнес.Добавить();
			стр.Показатель = Excel.Cells(б, НачКолонка).Value;	// F
			стр.Нижняя = Excel.Cells(б, НачКолонка+1).Value;	// G
			стр.Целевое = Excel.Cells(б, НачКолонка+2).Value;	// H
			стр.Верхняя = Excel.Cells(б, НачКолонка+3).Value;	// I
			стр.Факт = Excel.Cells(б, НачКолонка+4).Value;		// J
		КонецЦикла;
	Иначе
		Сообщить("Бизнес показатели - не загружены");
	КонецЕсли;
	
	
	НачСтрока = 0; НачКолонка = 0; КонСтрока = 0;
	Если ПолучитьRowColДиапазона(Sheet, "kriterii", НачСтрока, НачКолонка, КонСтрока, "$J$15:$K$18") Тогда
		тчКритерии = Объект.Критерии;
		тчКритерии.Очистить(); 
		// Критерии J15 : K18 
		Для б=НачСтрока по КонСтрока Цикл
			стр = тчКритерии.Добавить();
			стр.Оценка  = Excel.Cells(б, НачКолонка).Value;		// J
			стр.Процент = Excel.Cells(б, НачКолонка+1).Value;	// K		
		КонецЦикла;
	Иначе
		Сообщить("Критерии - не загружены");
	КонецЕсли;
	
	
	НачСтрока = 0; НачКолонка = 0; КонСтрока = 0;
	Если ПолучитьRowColДиапазона(Sheet, "ГраницыПремирования", НачСтрока, НачКолонка, КонСтрока, "$N$10:$O$12")	Тогда
		тчГраницыПремирования = Объект.ГраницыПремирования;
		тчГраницыПремирования.Очистить();
		// Критерии N10 : O12 
		Для б=НачСтрока по КонСтрока Цикл
			стр = тчГраницыПремирования.Добавить();
			стр.Процент = Excel.Cells(б, НачКолонка).Value;		// N
			стр.Граница = Excel.Cells(б, НачКолонка+1).Value;	// O		
		КонецЦикла;
	Иначе
		Сообщить("Границы премирования - не загружены");
	КонецЕсли;
	
	// Excel.ActiveWorkbook.Save();
	Excel.ActiveWorkbook.Close();
	Возврат Истина;
КонецФункции

&НаКлиенте
Функция ПолучитьRowColДиапазона(Sheet, ИменованныйДиапазон, НачСтрока, НачКолонка, КонСтрока, АдресДиапазонаПоУмолчанию=Неопределено)
	Попытка
		Адр = Sheet.Range(ИменованныйДиапазон).Address;	// $F$4:$J$7
	Исключение
		Адр = АдресДиапазонаПоУмолчанию;
	КонецПопытки;
	Если Адр = Неопределено Тогда
		ДиапазонПолучен = Ложь;
	Иначе
		Разделитель = Найти(Адр,":");
		Если Разделитель = 0 Тогда
			ЛевАдр = Адр;
			ПравАдр = Адр;
		Иначе
			ЛевАдр = Лев(Адр, Разделитель - 1);
			ПравАдр= Сред(Адр,Разделитель + 1);
		КонецЕсли;
		
		S = Найти(ЛевАдр,"$");
		ЛевАдр= Сред(ЛевАдр, S + 1);
		S = Найти(ЛевАдр,"$");	
		ЛевАдрКолонка = Лев(ЛевАдр, S - 1);	// F
		ЛевАдрРяд = Сред(ЛевАдр, S + 1);	// 4
		
		S = Найти(ПравАдр,"$");
		ПравАдр = Сред(ПравАдр, S + 1);
		S = Найти(ПравАдр,"$");
		ПравАдрКолонка = Лев(ПравАдр, S-1);	// J
		ПравАдрРяд = Сред(ПравАдр, S + 1);	// 7
		
		НачКолонка = КодСимвола(ЛевАдрКолонка) - КодСимвола("A") + 1;
		НачСтрока = Число(ЛевАдрРяд);
		КонСтрока = Число(ПравАдрРяд);
		ДиапазонПолучен = Истина;
	КонецЕсли;
	
	Возврат ДиапазонПолучен;
КонецФункции
Показать
3. SantiouS 17.08.20 11:33 Сейчас в теме
(2)
COMОбъект


Спасибо. Общая суть - это чтение файла через сам COMОбъект екселя? По другому никак?
6. Goleff74 216 17.08.20 11:42 Сейчас в теме
(3)
Эксель - это запакованный XML файл. Распарсите его на клиенте последовательно и сравнивайте.
8. SantiouS 17.08.20 13:08 Сейчас в теме
(6)
Эксель - это запакова

Звучит зловеще. Интересно посмотреть на реализацию, есть пример?
9. Goleff74 216 17.08.20 13:14 Сейчас в теме
(8)
Поменяйте расширение xlsx на zip. Внутр увидите файлы, составляющие эксель. XML-файлы структуры, словаря, объединений строк и т.п.
Любой xlsx раззипуйте и исследуйте :)
SantiouS; +1 Ответить
10. SantiouS 17.08.20 13:43 Сейчас в теме
(9) Круто, не знал. Спасибо)
7. Vitaly1C8 17.08.20 11:55 Сейчас в теме
(3) Как правило на клиенте (где сидит юзер) установлен Эксель. Юзер может открыть файл, посмотреть и изменить его.
А значит и COMОбъект экселя - зарегистрирован в системе. И парсить не имеет смысла, легче через COMОбъект
11. starik-2005 3042 17.08.20 15:01 Сейчас в теме
Можно прочитать файл на сервере в табличный документ, являющийся реквизитом формы, а потом к этому реквизиту формы ограниченно можно достучаться и на клиенте. Не сохраняя файл Excel не получится его прочитать в табличный документ - глюк платформы, походу. Можно xlsx распаковать на клиенте чтением ZIP, оттуда выдрать сам документ и работать с ним, как с XML - вполне рабочий вариант, но придется несколько повозиться с интерпретацией XML.
SantiouS; +1 Ответить
12. SantiouS 17.08.20 15:29 Сейчас в теме
(11) Спасибо Вам за развёрнутый ответ. Выделил для себя то, что код, написанный мною в шапке темы достаточен для меня. Однако всё равно узнал много других вариантов и, возможно, когда то они обязательно пригодятся :)
Оставьте свое сообщение

Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот