Чудесатые чудеса с выгрузкой заказов между 1С и Bitrix

Началось всё с того, что после настройки обмена мeжду Bitrix и 1С, заказы в 1С не прилетали. Посмотрел логи, подебажил код обмена и , увидел чудную ошибку «Transferred a partial file» при попытке получить файл заказов. Что при файловом варианте, что при серверном. Причем из браузера (по этой методике), файл открывался и корректно формировался. Просмотр логов сервера apache, добавил еще одну ошибку:

2021/07/14 08:54:49 [error] 27470#27470: *1517 upstream prematurely closed connection while reading upstream, client: 185.24.213.2, server: market.erfwerf.ru, request: "GET /bitrix/admin/1c_exchange.php?type=sale&mode=query&sessid=ca16a85220fc41bc7e7815adf4401d35 HTTP/1.1", upstream: "http://127.0.0.1:8083/bitrix/admin/1c_exchange.php?type=sale&mode=query&sessid=ca16a85220fc41bc7e7815adf4401d35", host: "market.ewrfewrf.ru"

Гуглинг объяснил, что это возможно ошибка в настройках ngnix. Совместно с хостером, попытались пару настроек изменить, после чего хостер сказал «ничё не знаю, у нас всё нормально». Доступа к настройкам сервера к сожалению нет — только через хостера.

Чего делать? Ну для начала решил попробовать файл формировать самостоятельно, и подпихивать его как то уже готовым в 1С. Наваял скрипт вида:

<?php
$login_url = 'https://market.ауцкацука.ru/bitrix/admin/1c_exchange.php?type=catalog&mode=checkauth';    
$post_data = 'AUTH_FORM=Y&TYPE=AUTH&USER_LOGIN=цукацук@цукацук.ru&USER_PASSWORD=кцуацукац';    
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $login_url );
curl_setopt($ch, CURLOPT_POST, 1 );
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookie.txt');
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookie.txt');
$postResult = curl_exec($ch);
$exa=explode("=",$postResult); 
$exa=explode("\n",$exa[1]);
$ssid=$exa[0];
curl_setopt($ch, CURLOPT_URL, "https://уцкацук.цукацука.ru/bitrix/admin/1c_exchange.php?type=sale&mode=query&sessid=".$ssid);
header('Content-Type: text/xml; charset=windows-1251');    
$postResult = curl_exec($ch);
echo $postResult;

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

В 1С попробовал:

Запрос = Новый HTTPЗапрос("/цукаука.php");
		Соединение = Новый HTTPСоединение("цкуацук.ауцкацу.ru",443,,,,1800,ОбщегоНазначенияКлиентСервер.НовоеЗащищенноеСоединение());    
		ОтветСервера=Соединение.ОтправитьДляОбработки(Запрос).ПолучитьТелоКакСтроку();

И получил ровно ту-же ошибку в 1С: Transferred a partial file. Шта??? Круг подозреваемых сузился. Стал винить во всем реализацию HTTPСоединение в 1С. А что если попробовать изобрести свою замену? Родил врезку в модуль обмена с сайтом:

   Если ОтветСервера = Неопределено Тогда    
		WinHttp = New COMОбъект("WinHttp.WinHttpRequest.5.1");
		WinHttp.Option(2,"utf-8");
		WinHttp.Open("GET", "https://maквеиеивкt.квеивкеимвек.ru/gквеивкеs.php", false);
		WinHttp.Send();
		Если WinHttp.Status = 200 Тогда
		    Stream = Новый COMОбъект("ADODB.Stream");
		    Stream.Type = 1;
		    Stream.Mode = 3;
			ОтветСервера=WinHttp.ResponseText;
		    Stream = Неопределено;
		КонецЕсли;						
	конецесли;

Работает.. Заказы в 1С появились..

1СЖ:Ошибка импорта товара на сайт

Ошибка: Ошибка импорта метаданных.В редакции Малый Бизнес нет возможности иметь более одного типа цены. Настройте выгрузку из 1С или перейдите на другую редакцию БУС

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

1c: сохранение настроек формы внешней обработки

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

Решение: на события ПриОткрытииНаСервере и при ПриЗакрытииНаСервере навсеми обработчики:

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

&НаСервере
Процедура ВосстановитьНастройкиНаСервере(КлючОбъекта, КлючНастроек, Пользователь = Неопределено)   
    СтруктураНастроек = Неопределено;
    Попытка
        СтруктураНастроек = ХранилищеОбщихНастроек.Загрузить(КлючОбъекта,КлючНастроек, ,Пользователь);
    Исключение
        Сообщить(ОписаниеОшибки());
    КонецПопытки;    
    Если СтруктураНастроек <> Неопределено Тогда
        Для Каждого Настройка Из СтруктураНастроек Цикл
            Если Объект.Свойство(Настройка.Ключ) Тогда 
                Объект[Настройка.Ключ] = Настройка.Значение;
            Иначе
                ЭтаФорма[Настройка.Ключ] = Настройка.Значение;
            КонецЕсли;
        КонецЦикла;
    КонецЕсли;
КонецПроцедуры

&НаСервере
Процедура УдалитьНастройкиНаСервере(КлючОбъекта, КлючНастроек, Пользователь = Неопределено)
    ХранилищеОбщихНастроек.Удалить(КлючОбъекта, КлючНастроек, Пользователь);
    Сообщить("Настройки " + КлючОбъекта + " для " + Пользователь + " удалены"); 
КонецПроцедуры

&НаСервере
Процедура ПриЗакрытииНаСервере()
	СохранитьНастройкиНаСервере("СохранениеНастроекПользователяФорма", "ВсеНастройки", ПользователиИнформационнойБазы.ТекущийПользователь());
КонецПроцедуры

&НаКлиенте
Процедура ПриЗакрытии(ЗавершениеРаботы)
	ПриЗакрытииНаСервере();
КонецПроцедуры

&НаСервере
Процедура ПриОткрытииНаСервере()
   ВосстановитьНастройкиНаСервере("СохранениеНастроекПользователяФорма", "ВсеНастройки", ПользователиИнформационнойБазы.ТекущийПользователь());
КонецПроцедуры

&НаКлиенте
Процедура ПриОткрытии(Отказ)
	ПриОткрытииНаСервере();
КонецПроцедуры

1С: Поиск пользователя по имени пользователя информационной базы.

Задача: найти пользователя из справочника «Пользователи» если известно только имя пользователя информационной базы.

Решение: воспользуемся стандартной функцией БСП ПользователиИнформационнойБазы:

			ПИБ=ПользователиИнформационнойБазы.НайтиПоИмени("Вася ВГ);
			Исполнитель=справочники.Пользователи.НайтиПоРеквизиту("ИдентификаторПользователяИБ",ПИБ.УникальныйИдентификатор);

Загрузка и обработка большого файла EXCEL в 1С с прогрессбаром

Задача: «фоново» загрузить файл эксель большого размера, с показом прогресса загрузки.

Решение:

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

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

В общих модулях разместим следующий код фонового процесса:

&НаСервере
Функция ЗагрузкаФайлаПредварительная(АдресВременногоХранилищаФайла) Экспорт			
	ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресВременногоХранилищаФайла);
	ИмяВременногоФайлаСпр = ПолучитьИмяВременногоФайла("xlsx");
	ДвоичныеДанные.Записать(ИмяВременногоФайлаСпр);     
	возврат ИмяВременногоФайлаСпр;	
конецфункции	

Процедура ЗагрузкаФайлаДлительная(ИмяВременногоФайлаСпр) Экспорт			
		
    ТабличныйДокументСпр = Новый ТабличныйДокумент;
    ТабличныйДокументСпр.Прочитать(ИмяВременногоФайлаСпр,СпособЧтенияЗначенийТабличногоДокумента.Значение);
	
	//читаем все листы файла СправочникСМС
	Для Каждого ОбластьТД ИЗ ТабличныйДокументСпр.Области Цикл         		     
            ОбластьФайла = ТабличныйДокументСпр.ПолучитьОбласть(ОбластьТД.Имя);
            КолВоСтрокФайла = ОбластьФайла.ПолучитьРазмерОбластиДанныхПоВертикали();
            КолВоКолонокФайла = ОбластьФайла.ПолучитьРазмерОбластиДанныхПоГоризонтали();
            Сообщить("Строк:"+КолВоСтрокФайла);
            Сообщить("Колонок:"+КолВоКолонокФайла);         
            имялиста=ОбластьТД.Имя;
            Сообщить("Лист:"+имялиста);         
                    МассивИменКолонок=Новый Массив();
                    // читаем шапку листа
                    Для ит=1 ПО КолВоКолонокФайла Цикл
                        нКолонка = СтрЗаменить(ит, Символы.НПП, "");
                        ИмяКолонки=ОбластьФайла.ПолучитьОбласть("R3" + "C"+нКолонка).ТекущаяОбласть.Текст;                        
                        МассивИменКолонок.Добавить(ИмяКолонки);
					конеццикла; 					
					НачСтрока=3;КонСтрока=0;
                    НачСтрока = ?(НачСтрока = 0, 2, НачСтрока);
                    КонСтрока = ?(КонСтрока = 0, КолвоСтрокФайла, КонСтрока);
                    //перебираем все строки без первой строки  
					Индикатор=0;
                    Для нСтрокаТФ = НачСтрока+1 ПО КонСтрока Цикл
                        нСтрока = СтрЗаменить(нСтрокаТФ, Символы.НПП, "");                        
			если Окр(нСтрокаТФ*100/КонСтрока)<>Индикатор тогда
				Индикатор = Окр(нСтрокаТФ*100/КонСтрока);
				Сообщение = Новый СообщениеПользователю;
				Сообщение.Текст = "Выполнено %"+Индикатор;
				Сообщение.Сообщить();
			конецесли;
			Для нКолонкаТФ = 1 ПО КолВоКолонокФайла Цикл
                            нКолонка = СтрЗаменить(нКолонкаТФ, Символы.НПП, "");
                            Область = ОбластьФайла.ПолучитьОбласть("R"+нСтрока+"C"+нКолонка);
                            ТекущаяОбласть = Область.ТекущаяОбласть;
                            ЗначениеЯчейки = СокрЛП(ТекущаяОбласть.Текст);
			    ...
				обрабатываем файл
			    ...	
                        конеццикла;                         		
	конеццикла;
	Сообщение = Новый СообщениеПользователю;
	Сообщение.Текст = "Загрузка завершена.";
	Сообщение.Сообщить();

Клиентская часть в управляемых формах:

&НаКлиенте
Процедура Жмяк(Команда)
Режим = РежимДиалогаВыбораФайла.Открытие;
    ДиалогОткрытияФайла = Новый ДиалогВыбораФайла(Режим);
    ДиалогОткрытияФайла.ПолноеИмяФайла = "";
    Фильтр = НСтр("ru = 'Текст'; en = 'Text'")+ "(*.xls)|*.xlsx";
    ДиалогОткрытияФайла.Фильтр = Фильтр;
    ДиалогОткрытияФайла.МножественныйВыбор = ложь;
    ДиалогОткрытияФайла.Заголовок = "Выберите файлы";
    Если ДиалогОткрытияФайла.Выбрать() Тогда
        МассивФайлов = ДиалогОткрытияФайла.ВыбранныеФайлы;
		ФайлСМС="";
		Для Каждого ИмяФайла Из МассивФайлов Цикл
			ФайлСМС=ИмяФайла;
		конеццикла;
		если ФайлСМС<>"" тогда 			
					АдресХранилищаФайла = "";			
					Состояние("Перемещаю файл на сервер");
		            ПоместитьФайл(АдресХранилищаФайла, ФайлСМС, , Ложь, ЭтаФорма.УникальныйИдентификатор);   					
					Состояние("Обрабатывается файл "+ФайлСМС);							
					ЗапускФоновойЗагрузкиСправочника(АдресХранилищаФайла);					
					Состояние("Запущена фоновая обработка файла");
					ПодключитьОбработчикОжидания("ИндикаторВыполненияЗагрузки",1,ложь);	
		иначе
			сообщить("Файл не выбран");
		конецесли;	
	конецесли;	        

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


&НаСервере
Процедура ЗапускФоновойЗагрузкиСправочника(АдресХранилищаФайла)	
	ИмяВременногоФайлаСпр=СК_Регламентные.ЗагрузкаФайлаПредварительная(АдресХранилищаФайла);	
	МассивПараметров = Новый Массив;
	МассивПараметров.Добавить(ИмяВременногоФайлаСпр);		
	Сообщить("Адрес файла (1):"+АдресХранилищаФайла);									
	ФЗ = ФоновыеЗадания.Выполнить("СК_Регламентные.ЗагрузкаФайлаДлительная",МассивПараметров);	
	ЭтаФорма.ФоновоеИдентификатор = ФЗ.УникальныйИдентификатор;
	
							
КонецПроцедуры
&НаСервере
Функция ПолучитьСообщенияФЗ(ФЗ, Состояние = Неопределено, УдалятьСообщения = Ложь) Экспорт
	Если Состояние = Неопределено Тогда
		Состояние = ФЗ.Состояние;
	КонецЕсли;
	МассивСообщений = Новый Массив;
	Сообщения = ФЗ.ПолучитьСообщенияПользователю(УдалятьСообщения);
	Если Сообщения <> Неопределено Тогда
		Для Каждого Сообщение Из Сообщения Цикл
			МассивСообщений.Добавить(Сообщение.Текст);
		КонецЦикла;
	КонецЕсли;
	Возврат МассивСообщений;
КонецФункции

&НаСервере
Функция ОпроситьФоновые()
	прог=неопределено;
	ФЗ = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(ЭтаФорма.ФоновоеИдентификатор);
	ФСообщения=ПолучитьСообщенияФЗ(ФЗ,,истина);
	Если ФСообщения.Количество() > 0 Тогда
		Для Каждого Сообщение Из ФСообщения Цикл
			Сообщить(Сообщение);
			если найти(Сообщение,"%")>0 тогда
				Этаформа.Прогресс=СтрЗаменить(Сообщение,"Выполнено %","");			
				прог=Этаформа.Прогресс;
			конецесли;
		КонецЦикла;
	КонецЕсли;
	возврат прог;
КонецФункции
&НаКлиенте
Процедура ИндикаторВыполненияЗагрузки() Экспорт
	пр=ОпроситьФоновые();
	если пр<>неопределено тогда
		Состояние("Выполнено "+пр);
	конецесли;
КонецПроцедуры
1 18 19 20 21 22 50