Thursday, December 4, 2014

1С и все такое: 1С:JSON парсер и сериализатор

1С и все такое: 1С:JSON парсер и сериализатор: JSON парсер и сериализатор c полной поддержкой стандарта, широким набором сериализуемых типов и продвинутым синтаксический анализатором...

Friday, October 24, 2014

1С БСП История изменений

Ссылка на подсистему версионирования объектов http://1clancer.ru/article/bsp_-_podsistema_versionirovanie_obektov_1185

Добавление в конфигурацию поддержки присоединенных файлов

Для каждого «объекта с файлами» выполнить настройку:

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

<Префикс>ПрисоединенныеФайлы,

где <Префикс> – имя объекта метаданных, для которого настраиваются присоединенные файлы. Например, для справочника Номенклатура справочник с файлами должен называться НоменклатураПрисоединенныеФайлы. Задать синоним, например: Присоединенные файлы (Номенклатура).

2. У реквизита ВладелецФайла установить тип – «объект с файлами». Например, СправочникСсылка.Номенклатура.

3. Измерению ОбъектСФайлами регистра сведений НаличиеПрисоединенныхФайлов, установить тип – «объект с файлами». Например, СправочникСсылка.Номенклатура

4. В состав типов измерения ПрисоединенныйФайл регистра сведения ПрисоединенныеФайлы включить справочник, созданный на шаге 1. Например, СправочникСсылка.НоменклатураПрисоединенныеФайлы.

5. Расширить тип параметра общей команды ПрисоединенныеФайлыКОбъекту, добавив в него тип – «объект с файлами». Например: СправочникСсылка.Номенклатура.

6. Расширить состав типов свойства Источник у подписок ПрисоединенныйФайлПередЗаписью, ПрисоединенныйФайлПередУдалением, ПрисоединенныйФайлПриЗаписи, включив в него тип – справочник с файлами, созданный на шаге 1. Например, СправочникОбъект.НоменклатураПрисоединенныеФайлы

7. Расширить состав типов свойства Источник подписки УстановитьПометкуУдаленияПрисоединенныхФайлов включив в него тип – «объект с файлами». Например, СправочникОбъект.Номенклатура.

Tuesday, August 5, 2014

Получение smtp адреса(реального) почты при работе с exchange через outlook

Дальнейшая доработка по работе с прайсами. Исходя из раньше описанной задачи необходимо обработать почту через outlook, а после отправить отправителю ответ уже средствами самой 1С в виде предварительно подготовленного прайса. Посмотрев то что дает в ответ outlook, я увидел вот такой адрес "/O=company/OU=EXCHANGE ADMINISTRATIVE GROUP (FYDIBOHF23SPDLT)/CN=RECIPIENTS/CN=USERBD7FBB0A",что совсем не подходит для работы SMTP. Как итог была переделана процедура из c# в 1с для обработки адреса:

Если ВРег(mail.SenderEmailType) = "EX" тогда
    recip = objNamespace.CreateRecipient(mail.SenderEmailAddress);
    exUser = recip.AddressEntry.GetExchangeUser();
    sAddress = exUser.PrimarySmtpAddress;
Иначе
    sAddress = mail.SenderEmailAddress
КонецЕсли;

Friday, August 1, 2014

Автоматическая загрузка прайса и работа с ФорматированныйДокумент

Есть у меня почтовая рассылка прайс листов из 1с. Сделана она с использованием ФорматированныйДокумент.
Лень, как известно двигатель прогресса, в общем надоело мне грузить картинки в рассылки каждый раз вручную, и задумался я над тем как сделать это все автоматом...
В общем логика состоит в том, что маркетинг высылаем письмо роботу на почту, робот почту анализирует и создает документ рассылки.
Нарвался на трудность в форматируемом документе, это отсутствие возможности отцентровать текст (сделать по центру). Решения в нете не нашел, сделал свое.

ТелоРассылки.ПолучитьHTML(ТекстHTML,Вложения);
			ТекстHTML = СтрЗаменить(ТекстHTML,"","
"center"">
"
); ТелоРассылки.УстановитьHTML(ТекстHTML,Вложения);

А ниже уже обработка по загрузке с почты прайсов.


Процедура КомандаGetНаСервере()
	//НЕ забываем проверить как запускает оутглюк!!!!  runas /user:rl\usr1cv82 "C:\Program Files\Microsoft Office\Office15\outlook.exe"
	//
	
	
	RegExp = Новый COMОбъект("VBScript.RegExp");
	//СтруктураФайлов = Новый СписокЗначений;
	RegExp.MultiLine = Истина; // истина — текст многострочный, ложь — одна строка 
	RegExp.Global = Истина; // истина — поиск по всей строке, ложь — до первого совпадения 
	RegExp.IgnoreCase = Истина; // истина — игнорировать регистр строки при поиске 	
	RegExp.Pattern = "Дата:.*(\d{4})/(\d{1,2})/(\d{1,2})";
	
	
	
	olFolderInbox = 6;
	Попытка
		objOutlook = Новый COMОбъект("Outlook.Application");
	Исключение
		objOutlook = НЕопределено;
		//Сообщить("Не удалось создать объект Outlook.Application. Outlook установлен на компьютер?");
		Возврат;
	КонецПопытки;
	
	objNamespace = objOutlook.GetNamespace("MAPI");
	objFolderInbox = objNamespace.GetDefaultFolder(olFolderInbox);
	colMails = objFolderInbox.Items.Restrict("[unread] = true");
	Для каждого mail из colMails Цикл
		попытка
			Body = mail.HTMLBody;
		Исключение
			Body = mail.Body;
		КонецПопытки;
    	Matches=RegExp.Execute(Body);
		Если RegExp.Test(Body) тогда
			Год = Matches.Item(0).SubMatches.Item(0);
			Если СтрДлина(Год)=2 тогда
				Год="20"+Год;
			КонецЕсли;
			Месяц = Формат(Matches.Item(0).SubMatches.Item(1),"ЧН=0; ЧВН=");	
			День = Формат(Matches.Item(0).SubMatches.Item(2),"ЧН=0; ЧВН=");	
			Path = "\\srv-1c-01.rl.int\Price\"+Год+Месяц+День;
			for each File in НайтиФайлы(Path,,true) do
				If не File.Name="Thumbs.db" then
					УдалитьФайлы(File.FullName);
				Endif;
			EndDo;
			Если НайтиФайлы(Path).Количество()=0 тогда
				СоздатьКаталог(Path);
			КонецЕсли;
			
			ДокСсылка  = ПроверкаДокументаВБазе(Дата(Год,Месяц,День));
			Если НЕ ДокСсылка.Пустая() тогда
				ДокОбъект = ДокСсылка.ПолучитьОбъект();
			Иначе
				ДокОбъект = Документы.РассылкаПрайсЛистов.СоздатьДокумент();
			КонецЕсли;
			ДокОбъект.Дата = Дата(Год,Месяц,День);
			ДокОбъект.ДатаОтправки = Дата(Год,Месяц,День)+8*60*60;
			ДОкОбъект.Ответственный = Справочники.Пользователи.ПолучитьСсылку(Новый УникальныйИдентификатор("d57cf6b5-3dcd-11e1-80e4-00155d040a09"));
			ДОкОбъект.Автор = Справочники.Пользователи.ПолучитьСсылку(Новый УникальныйИдентификатор("d57cf6b5-3dcd-11e1-80e4-00155d040a09"));
			ДокОбъект.Статус = Перечисления.СтатусыРассылкиПрайса.Согласован;
			ДокОбъект.Комментарий = "Сформирован автоматом "+ Формат(ТекущаяДата(),"ДФ='dd.MM.yyyy HH:mm:ss'");
			ДокОбъект.Тема = "Ежедневная рассылка прайс-листа  "+Формат(ДокОбъект.Дата,"ДФ='ддд dd/MM/yyyy'");
			ТелоРассылки = Новый ФорматированныйДокумент;
			ТекстHTML = Неопределено;
			Вложения = Неопределено;
						
			ТелоРассылки.ПолучитьHTML(ТекстHTML,Вложения);
			ТекстHTML = СтрЗаменить(ТекстHTML,"","
"center"">
"
); ТелоРассылки.УстановитьHTML(ТекстHTML,Вложения); ЕстьЧтоДобавлять = Ложь; For each Att in mail.Attachments do If Lower(Left(Att.FileName,5))="image" then Continue; EndIf; If Find("jpg,png,bmp,gif",Right(Att.FileName,3))> 0 then ЕстьЧтоДобавлять = Истина; Att.SaveAsFile(Path+"\"+Att.FileName); ТелоРассылки.Добавить(,ТипЭлементаФорматированногоДокумента.ПереводСтроки); ТелоРассылки.Добавить(Новый Картинка(Path+"\"+Att.FileName), ТипЭлементаФорматированногоДокумента.Картинка); endif; EndDo; ДокОбъект.Тело = Новый ХранилищеЗначения(ТелоРассылки,Новый СжатиеДанных(9)); ДокОбъект.Записать(РежимЗаписиДокумента.Проведение); КонецЕсли; КонецЦикла; //закрываем соединение Попытка objNamespace.Logoff(); objOutlook.Quit(); Исключение КонецПопытки; objNamespace = Неопределено; objFolderInbox = неопределено; objOutlook = НЕопределено; colMails = Неопределено; КонецПроцедуры Функция ПроверкаДокументаВБазе(ДатаДок) Запрос = Новый Запрос; Запрос.Текст = "ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 1 | РассылкаПрайсЛистов.Ссылка |ИЗ | Документ.РассылкаПрайсЛистов КАК РассылкаПрайсЛистов |ГДЕ | НЕ РассылкаПрайсЛистов.ПометкаУдаления | И НАЧАЛОПЕРИОДА(РассылкаПрайсЛистов.Дата, ДЕНЬ) = &Дата"; Запрос.УстановитьПараметр("Дата", ДатаДок); РезультатЗапроса = Запрос.Выполнить(); ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать(); Если ВыборкаДетальныеЗаписи.Следующий() Тогда Возврат ВыборкаДетальныеЗаписи.Ссылка; КонецЕсли; Возврат Документы.РассылкаПрайсЛистов.ПустаяСсылка(); КонецФункции
Работает это все на Windows 2008R2 x64 c Microsoft Office x64, outlook x64. и работает нормально, главное не забыть отключить безопасность в outlook.

Tuesday, July 29, 2014

Генератор паролей в 1С с проверкой сложности

Задали мне задачку импортировать пользователей в Битрикс с требование генерации сложных паролей с 1С. Импорт с Битрикс отдельная тема, а вот сложные пароли и их валидность опишу тут.
Фактически требование сводилось к мин количеству символов = 8, должны быть буквы нижнего и верхнего регистра, цифры и спец. символы.
Вот что из этого получилось:

Функция СгенерироватьПароль(МинДлинаПароля=8, СложныйПароль=Истина)
 ПарольВалиден = Ложь;
 
 Пока НЕ ПарольВалиден Цикл
  ГСЧ = Новый ГенераторСлучайныхЧисел(Секунда(ТекущаяДата()));
  ТПароль = СтрЗаменить(Строка(Новый УникальныйИдентификатор()),"-","");
  
  Если не СложныйПароль тогда
   Возврат Лев(ТПароль,МинДлинаПароля);
  Иначе
   НобходимыеСимволяДляСложности = ".,<>/?;:'[]{}\`~!@#$%^&*()-_+=";
   МаксСимволов  =  МинДлинаПароля+ГСЧ.СлучайноеЧисло(0,4);
   ТПароль = Лев(ТПароль,МаксСимволов);
   Для Сим=1 по МаксСимволов Цикл
    Если Сим>1 И Булево(ГСЧ.СлучайноеЧисло(0,1)) И Найти(НобходимыеСимволяДляСложности,Сред(ТПароль,Сим-1,1))=0 тогда
     ТПароль = Лев(ТПароль,Сим)+Сред(НобходимыеСимволяДляСложности,ГСЧ.СлучайноеЧисло(0,30),1)+Сред(ТПароль,Сим+1);
     Сим = Сим+1;
     ТПароль = Сред(ТПароль,1,МаксСимволов);
    КонецЕсли;
    Если Булево(ГСЧ.СлучайноеЧисло(0,1)) тогда
     ТПароль = Лев(ТПароль,Сим-1)+ВРег(Сред(ТПароль,Сим,1))+Сред(ТПароль,Сим+1);
    КонецЕсли;
   КонецЦикла;
  КонецЕсли;
  
  //Проверка валидности пароля
  //((?=.*[a-z])(?=.*\d)(?=.*[\.,<>/\?;:'\[\]\{\}\\`~!@#$%^&*()-_+=])(?=.*[A-Z]).{6,})
  
  RegExp = Новый COMОбъект("VBScript.RegExp");
  //СтруктураФайлов = Новый СписокЗначений;
  RegExp.MultiLine = Истина; // истина — текст многострочный, ложь — одна строка 
  RegExp.Global = Истина; // истина — поиск по всей строке, ложь — до первого совпадения 
  RegExp.IgnoreCase = Ложь; // истина — игнорировать регистр строки при поиске 
  RegExp.Pattern = "^((?=.*[a-z])(?=.*\d)(?=.*[\.,<>/\?;:'\[\]\{\}\\`~!@#$%^&\*()-_+=])(?=.*[A-Z]).{8,})$";
  ПарольВалиден = RegExp.Test(ТПароль);
 КонецЦикла;
 Возврат ТПароль;
КонецФункции

Monday, July 21, 2014

Формирование отчета СКД с картинками в управляемых формах 1С УТ11

Поставили мне задачу сформировать отчет с картинками. Очень давно пользуюсь СКД, но как то нормально у системы с картинками не сложилось. поэтому пришлось гуглить.
Как итог вид отчета

Натолкнулся на проблему, в нете все решения сделаны базово. Мне необходимо было сделать так что бы была возможность выводить несколько изображений и они не были привязаны к определенным колонкам.
Фактически необходимо показать изображение которое стоит основным в справочнике номенклатуры, а также все изображения из справочника "ПрисоединенныеФайлы". В этой обработке возможно будет ошибка, так как я не проверяю, это картинка или нет, необходимо доделывать проверку.

В итоге запрос из схемы компоновки данных:

ВЫБРАТЬ
НоменклатураПрисоединенныеФайлы.Ссылка КАК Файл,
НоменклатураПрисоединенныеФайлы.ВидФайла,
НоменклатураПрисоединенныеФайлы.ФайлХранилище,
НоменклатураПрисоединенныеФайлы.ВладелецФайла,
ПрисоединенныеФайлы.ХранимыйФайл КАК Картинка,
СпрНоменклатура.Ссылка КАК Номенклатура,
ПрисоединенныеФайлы.ХранимыйФайл КАК КоличествоФайлов,
СпрНоменклатура.Ссылка КАК КоличествоНоменклатуры,
НоменклатураПрисоединенныеФайлы.ВладелецФайла КАК КоличествоНоменклатурыСФайлами,
СпрНоменклатура.ФайлКартинки
ИЗ
Справочник.Номенклатура КАК СпрНоменклатура
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.НоменклатураПрисоединенныеФайлы КАК НоменклатураПрисоединенныеФайлы
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПрисоединенныеФайлы КАК ПрисоединенныеФайлы
ПО НоменклатураПрисоединенныеФайлы.Ссылка = ПрисоединенныеФайлы.ПрисоединенныйФайл
ПО СпрНоменклатура.Ссылка = НоменклатураПрисоединенныеФайлы.ВладелецФайла
Плюсом к моей задаче необходимо было оценить сколько файлов прикреплено.
Добавляем параметр ширину колонки, для красоты вывода
И оформляем настройки


Выводим только заполненные дополнительные строки


И код модуля




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

Процедура ВывестиИзображениеЭлементаНоменклатуры(ТД, ЭлементСправочника, Область, ШиринаКолонкиИзображения)
 Если ЭлементСправочника.ТипХраненияФайла = Перечисления.ТипыХраненияФайлов.ВИнформационнойБазе Тогда
  СтуктураРег = РегистрыСведений.ПрисоединенныеФайлы.Получить(Новый Структура("ПрисоединенныйФайл,ВидФайла", ЭлементСправочника,ЭлементСправочника.ВидФайла));
  ДанныеКартинки = СтуктураРег.ХранимыйФайл.Получить();
 Иначе
  ДанныеКартинки = ?(ЗначениеЗаполнено(ЭлементСправочника.Том.ПолныйПутьWindows), ЭлементСправочника.Том.ПолныйПутьWindows, ЭлементСправочника.Том.ПолныйПутьLinux)
  + ЭлементСправочника.ПутьКФайлу;
 КонецЕсли;
 Рисунок = ВывестиИзображениеВОбластиТД(ДанныеКартинки, ТД, Область);
 Область.АвтоВысотаСтроки = Ложь;
 Область.ВысотаСтроки = ШиринаКолонкиИзображения * 1.31 / 0.3759;// Среднее значение пункта 1 пункт = 0.3759 мм (по Wiki)
 Область.Расшифровка = ЭлементСправочника;
 Рисунок.ЦветЛинии = Область.ЦветРамки;
КонецПроцедуры 


Функция ВывестиИзображениеВОбластиТД(ДанныеКартинки, ТД, Область)
 Изображение = ТД.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Картинка);
 Изображение.РазмерКартинки = РазмерКартинки.АвтоРазмер;
 Индекс = ТД.Рисунки.Индекс(Изображение);
 ТД.Рисунки[Индекс].Картинка = Новый Картинка(ДанныеКартинки, Истина);
 ТД.Рисунки[Индекс].Расположить(Область);
 Возврат ТД.Рисунки[Индекс]; 
КонецФункции


Функция ВернутьЗначениеПараметраНастройкиСКД(КоллекцияЭлементовНастройки, ИмяНастройки, ЗначениеПоУмолчанию = Неопределено)
 
 Настройка = КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы.Найти(ИмяНастройки);
 Если Настройка = Неопределено Тогда Возврат ЗначениеПоУмолчанию; КонецЕсли;
 НастрокаПоИД = КомпоновщикНастроек.ПользовательскиеНастройки.Элементы.Найти(Настройка.ИдентификаторПользовательскойНастройки);
 Если Не ЗначениеЗаполнено(НастрокаПоИД.Значение) Тогда 
  Если Не ЗначениеПоУмолчанию = Неопределено Тогда
   НастрокаПоИД.Значение = ЗначениеПоУмолчанию;
  КонецЕсли;
 КонецЕсли;
 Возврат ?(НастрокаПоИД.Использование, НастрокаПоИД.Значение, ЗначениеПоУмолчанию); 
КонецФункции


Monday, September 23, 2013

Программно установить в 1С 8.2 блокировку регламентных заданий

Возникла проблема с УТ11, при установке блокировки пользователей, надо не забывать устанавливать вручную в консоли администрирования серверов в определенной базе «галку» по блокировке регламентных задач.
Порывшись с нете однозначного решения как это сделать не нашел, поэтому предлагаю свой версию доработки:




Exported from Notepad++



// Установить или снять блокировку информационной базы,
// исходя из значений реквизитов обработки.
//
Процедура ВыполнитьУстановку() Экспорт

Блокировка = Новый БлокировкаСеансов;
Блокировка.Начало = НачалоДействияБлокировки;
Блокировка.Конец = ОкончаниеДействияБлокировки;
Блокировка.Сообщение = СоединенияИБ.СформироватьСообщениеБлокировки(Сообщение, КодРазрешения);
Блокировка.Установлена = БлокировкаУстановкиСоединенийВключена;
Блокировка.КодРазрешения = КодРазрешения;


УстановитьБлокировкуСеансов(Блокировка);

ТекСтруктураИмен = МастерПроцедурыСервера.ВозвратСтруктурыИменСервераИБазы();

ИмяСервера = ТекСтруктураИмен.ИмяСервера;
ИмяБазы = ТекСтруктураИмен.ИмяБазы;

Коннектор = Новый COMОбъект("v82.COMConnector");
Агент = Коннектор.ConnectAgent(ИмяСервера);
Кластеры = Агент.GetClusters();

Для каждого Кластер из Кластеры Цикл
АдминистраторКластера = "COMConnector";
ПарольКластера = "COMConnector";
Агент.Authenticate(Кластер, , );
Процессы = Агент.GetWorkingProcesses(Кластер);
Для каждого Процесс из Процессы Цикл

Порт = Процесс.MainPort;
// теперь есть адрес и порт для подключения к рабочему процессу
РабПроц = Коннектор.ConnectWorkingProcess(ИмяСервера + ":" + СтрЗаменить(Порт, Символы.НПП, ""));
РабПроц.AddAuthentication("ИмяПользователя", "ПарольПользователя");

ИнформационнаяБаза = "";

Базы = РабПроц.GetInfoBases();
Для каждого База из Базы Цикл
Если НРег(База.Name) = НРег(ИмяБазы) Тогда
База.ScheduledJobsDenied = БлокировкаУстановкиСоединенийВключена;
РабПроц.UpdateInfoBase(База);
ИнформационнаяБаза = База;
Прервать;
КонецЕсли;
КонецЦикла;

КонецЦикла;
КонецЦикла;

Коннектор = Неопределено;
Агент = Неопределено;
Кластеры = Неопределено;


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


Wednesday, September 18, 2013

Написание бота для icq или как работать xmpp протоколом используя gateway openfire сервера.

Решил я сделать бота для работы с аськой, основной задачей которого было бы делать рассылки менеджерам, а также напоминание и возможно формирования дополнительных ""плюшек". Основной проблемой стало то, что в организации повально используется icq как основное средство общения. В начале было решил работать с с протоколом oscar, но само время icq уже подходит на нет - реализацию через прямой протокол я прекратил, тем более в памяти возникали воспоминания, про то как icq меняла свой протокол и возникавшими проблемами у других клиентов.
Сейчас пытаюсь понять какой веб портал было бы оптимально использовать для работы, перерывая куча документации по порталам и всяким плюшкам к ним, я заметил, что большая часть чатов порталов работает с xmpp серверами и по xmpp протоколу.
Итого после долгих изучений и разговоров был поднят Openfire как xmpp сервер под AD, спасибо habr-у.
Следующий шаг поиск библиотеки под c#. Честно была шальная мысля все прикрутить к самой 1С, но опять обратившись к самому how-to и погуглив в нете, понял что занятие бесперспективное и опасное, основная проблема заключается как раз в работе icq. Поднятие несколько раз соединения для отправки письма клиенту icq будет проблемно, так как сервер icq начнет блокировать соединения.
Поэтому начал смотреть список библиотек под c#, так как было реализовано много проектов на c#.
Первая из них agxmpp имеет 2 типа лицензий и в принципе подходит. На сайте производителя есть также библиотека matrix, но она полностью коммерческая.

итого краткая история формирования:
1. Часть это не сильно долгий по времени, но слабо описанный в нете процесс подключение к openfire, методом научного тыка и перебора удалось подключиться и начать отправлять сообщения внутри сервера.
2. Самая большая проблема это отправка сообщения через транспорт(или же gateway), вот тут пришлось очень сильно повозиться,четкого и грамотного описания как это сделать нет, на сайте разработчиков, в теме с вопросом есть только несколько невнятных ответов без примеров(Тема1, Тема2), и очень скудная документация, зародившая желания написать библиотеку самому.
В итоге после пару дней поиска решения и возникшего желания перейти на другой протокол, нормальных протоколов по c# не было, а вот java были SMACK, после небольшого гугления было найдено решение.


Ну а теперь код под c# с использование библиотеки agxmpp:



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using agsXMPP;
using agsXMPP.protocol;
using agsXMPP.protocol.iq;
using agsXMPP.protocol.client;
using agsXMPP.sasl;


using System.Threading;

namespace ConsoleApplicationJabber
{
    class Program
    {
        static XmppClientConnection xmpp;
        static bool _wait;

        [STAThread]
        static void Main(string[] args)
        {
            
            string user = "user";
            string pass = "password";

            //Console.WriteLine("Press Key!");
            //Console.ReadLine();
            Jid jid = new Jid(user+"@domain");
            xmpp = new XmppClientConnection();
            xmpp.Server = jid.Server;
            xmpp.Username = jid.User;
            xmpp.ConnectServer = "NameServer.domain";
            xmpp.UseSSL = false;
            
            xmpp.AutoResolveConnectServer = false;
            xmpp.AutoPresence = false;
            xmpp.AutoRoster = false;
            xmpp.AutoAgents = false;


            xmpp.OnReadXml += new agsXMPP.XmlHandler(xmpp_OnReadXml);
            xmpp.OnWriteXml += new agsXMPP.XmlHandler(xmpp_OnWriteXml);
            xmpp.OnLogin += new ObjectHandler(xmpp_OnLogin);
            xmpp.OnError += new agsXMPP.ErrorHandler(xmpp_OnError);
            xmpp.OnSaslStart += new SaslEventHandler(XmppCon_OnSaslStart);
            xmpp.OnPresence += new PresenceHandler(xmpp_OnPresence);
            xmpp.OnMessage += new MessageHandler(xmpp_OnMessage);
            xmpp.OnAgentStart += new ObjectHandler(XmppCon_OnAgentStart);
            xmpp.OnAgentEnd += new ObjectHandler(XmppCon_OnAgentEnd);
            xmpp.OnAgentItem += new agsXMPP.XmppClientConnection.AgentHandler(XmppCon_OnAgentItem);
            xmpp.OnIq+= new IqHandler(xmpp_onIQ);

            try
            {
                xmpp.Open(user, pass, "ConsoleClient", 5);
             }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            Console.Write("Wait for Login ");
            _wait = true;
            int i=0;
            do
            {
                Console.Write(".");
                i++;
                if (i == 10)
                    _wait = false;
                Thread.Sleep(500);
            } while (_wait); 


            Presence p = new Presence(ShowType.chat, "Online");
            p.Type = PresenceType.available;
            
            xmpp.Send(p);

        
            xmpp.AutoAgents = false;

            IQ iq = new IQ();
            iq.Type = IqType.set;
            iq.To = new Jid("icq.domain"); // тут название трансопрта
            
            iq.SetAttribute("username","NumberICQ"); // номер icq
            iq.SetAttribute("password", "PasswordICQ"); 
            xmpp.Send(iq);

            Thread.Sleep(5000);

            xmpp.Send(new Message(new Jid("UserToICQ@icq.domain"), MessageType.chat, "Hello, how are you?" + DateTime.Now.ToLongTimeString()));

            

            //while (true)
            //{
            //    System.Threading.Thread.Sleep(100);
            //};

            Console.WriteLine("End work. Press Key!");
            
            xmpp.Close();
            Console.ReadLine();
        }



        static void xmpp_onIQ(object sender, IQ iq)
        {
          
        }


        static void XmppCon_OnAgentStart(object sender)
        {

        }

        static void XmppCon_OnAgentEnd(object sender)
        {

        }

        static void XmppCon_OnAgentItem(object sender, agsXMPP.protocol.iq.agent.Agent agent)
        {

        }


        static void xmpp_OnMessage(object sender, agsXMPP.protocol.client.Message msg)
        {
            if (msg.Body != null)
            {
                Console.ForegroundColor = ConsoleColor.Blue;
                Console.WriteLine("{0}>> {1}", msg.From.User, msg.Body);                
                Console.ResetColor();                
            }
        }

        static void xmpp_OnPresence(object sender, Presence pres)
        {
            Console.WriteLine("Available Contacts: ");
            Console.WriteLine("{0}@{1}  {2}",        pres.From.User,pres.From.Server,pres.Type);
            Console.WriteLine();            
        }

        static void MessageCallBack(object sender, agsXMPP.protocol.client.Message msg, object data)
        {
            if (msg.Body != null)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("{0}>> {1}", msg.From.User, msg.Body);
                Console.ResetColor();
                
               
                //Console.ForegroundColor = ConsoleColor.Green;
            }
        } 


        private static void XmppCon_OnSaslStart(object sender, SaslEventArgs args)
        {
            args.Auto = false;
            args.Mechanism = agsXMPP.protocol.sasl.Mechanism.GetMechanismName(agsXMPP.protocol.sasl.MechanismType.PLAIN);
        }

        private static void xmpp_OnLogin(object sender)
        {
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("ok");
            Console.WriteLine("we are logged in to the server now");
            Console.ResetColor();
            xmpp.SendMyPresence();
            
            _wait = false;
        }

        private static void xmpp_OnError(object sender, Exception ex)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(ex.Message);
            Console.ResetColor();
        }

        private static void xmpp_OnReadXml(object sender, string xml)
        {
            Console.ForegroundColor = ConsoleColor.Magenta;
            Console.WriteLine("RECV XML: " + xml);
            Console.ResetColor();
        }

        private static void xmpp_OnWriteXml(object sender, string xml)
        {
            Console.ForegroundColor = ConsoleColor.DarkMagenta;
            Console.WriteLine("SEND XML: " + xml);
            Console.ResetColor();
        }
    }
}

Friday, August 30, 2013

УТ 11. Формирования отчета по всем доп. реквизитам и сведениям и свойствам

М-дя, на морочили 1С-цы с доп. реквизитами. очень долго искал как сделать что бы красиво и хорошо, но нету нет даже детальных предложений или вариантов что бы посмотреть кто как делал, поэтому предлагаю свою версию. Первоначально это только отчет, а уже автоматическая система ввода и изменения будет сделана после.
Покопавшись в конфигурации, решил делать все на СКД, так быстрее и проще, поэтому запрос по выборке данных будет такой:

ВЫБРАТЬ
 СпрНоменклатура.Ссылка КАК Номенклатура,
 НаборыДополнительныхРеквизитовИСведенийДополнительныеРеквизиты.Свойство,
 НоменклатураДополнительныеРеквизиты.Значение
ИЗ
 Справочник.Номенклатура КАК СпрНоменклатура
  ЛЕВОЕ СОЕДИНЕНИЕ Справочник.НаборыДополнительныхРеквизитовИСведений.ДополнительныеРеквизиты КАК НаборыДополнительныхРеквизитовИСведенийДополнительныеРеквизиты
  ПО СпрНоменклатура.ВидНоменклатуры.НаборСвойств = НаборыДополнительныхРеквизитовИСведенийДополнительныеРеквизиты.Ссылка
  ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура.ДополнительныеРеквизиты КАК НоменклатураДополнительныеРеквизиты
  ПО СпрНоменклатура.Ссылка = НоменклатураДополнительныеРеквизиты.Ссылка
   И (НаборыДополнительныхРеквизитовИСведенийДополнительныеРеквизиты.Свойство = НоменклатураДополнительныеРеквизиты.Свойство)
ГДЕ
 НЕ СпрНоменклатура.ЭтоГруппа 
В данном случае выбираем всю номенклатуру, цыпляем справочник НаборыДополнительныхРеквизитовИСведений, и уже после к табличной части номенклатуры ДополнительныеРеквизиты. Получаем полную информацию что заполнено, а что нет.


Теперь настройки


Ну и как итог постоитель