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

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


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


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

Saturday, June 1, 2013

Функция для 1С Предприятие 8.х проверки правильности e-mail

&НаСервере
Функция ПроверитьEmail(СтрокаПочты)
                  Pattern = "^[-a-z0-9!#$%&'*+/=?^_`{|}~]+(?:\.[-a-z0-9!#$%&'*+/=?^_`{|}~]+)*@(?:[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?\.)*";
                  RegExp = Новый COMОбъект("VBScript.RegExp");
                  RegExp.IgnoreCase = Истина;
                  RegExp.Global = Истина;
                  RegExp.MultiLine = Ложь;
                  RegExp.Pattern = Pattern;
                  Возврат RegExp.Test(СтрокаПочты);
КонецФункции

Friday, April 19, 2013

Функция для возврата только числа из любой строки

Возникла ситуация, когда необходимо преобразовать в число любую строку из 1с или другого com объекта (excel,word и т.п.) при чем строки могут быть разные и содержать разные данные, функция написана, что бы быстро преобразовать в число.

Функция ВернутьЧисло(Знач ВхСтрока)

Если ТипЗнч(ВхСтрока) = Тип("Число") Тогда
Возврат ВхСтрока;
КонецЕсли;

Если НЕ ЗначениеЗаполнено(ВхСтрока) Тогда
Возврат 0;
КонецЕсли;
Если ТипЗнч(ВхСтрока) <> Тип("Строка") Тогда
Возврат 0;
КонецЕсли;

ВхСтрока = СтрЗаменить(ВхСтрока, ",", ".");

RegExp = Новый COMОбъект("VBScript.RegExp");

RegExp.MultiLine = Истина; // истина — текст многострочный, ложь — одна строка
RegExp.Global = Истина; // истина — поиск по всей строке, ложь — до первого совпадения
RegExp.IgnoreCase = Ложь; // истина — игнорировать регистр строки при поиске

RegExp.Pattern = "[^0-9\.-]";

Реплайс = RegExp.Replace(ВхСтрока,"");
Если пустаяСтрока(Реплайс) тогда
возврат 0;
КонецЕсли;

RegExp.Pattern = "[+-]?\d+\.?\d*";
Matches = RegExp.Execute(Реплайс);
Если Matches.Count>0 тогда
Возврат Число( Matches.Item(0).Value);
КонецЕсли;
Возврат 0;
КонецФункции

Thursday, March 14, 2013

Изменение стандартных кнопок на командной панели 1С 8.х обычное приложение

Столкнулся с проблемой, необходимо была к привязной к таблице командной панели, оставить только часть необходимых кнопок, + добавить часть своих. На просторах нета нашел решение данной проблемы, правда только для одной кнопки, в данном случае предлагаю код для нескольких. Если необходимо добавить другие кнопки, в конфигураторе на необходимой панели включаем АвтоЗаполнение, сщелкаем на кнопках которые появились на панели и вписываем их номер ("Действие1") в массив.

Мас=Новый Массив;
Мас.Добавить(ЭлементыФормы.КоманднаяПанель2.Кнопки.Действие5.Действие);
Мас.Добавить(ЭлементыФормы.КоманднаяПанель2.Кнопки.Действие6.Действие);
Мас.Добавить(ЭлементыФормы.КоманднаяПанель2.Кнопки.Действие7.Действие);
Мас.Добавить(ЭлементыФормы.КоманднаяПанель2.Кнопки.Действие8.Действие);
ЭлементыФормы.КоманднаяПанель2.АвтоЗаполнение = Ложь;
Для каждого знчМас из Мас Цикл
ЭлементыФормы.КоманднаяПанель2.Кнопки.Добавить(СтрЗаменить(Строка(знчМас)," ",""),ТипКнопкиКоманднойПанели.Действие,СтрЗаменить(Строка(знчМас)," ",""),знчМас);
КонецЦикла;

Saturday, March 2, 2013

Форматирование SQL запросов

Столкнулся с одной интересной проблемой, имел запрос sql который был вытащен с profiler sql. Имел очень не читабельный вид, можно было бы конечно воспользоваться редактором и прокладцать все самому, но было лень, тратить на эту работу время, при том что скрипт к конечном итоге занимал несколько страниц



Попытался было воспользоваться сторонними утилитами для редактирования была скачена утилитка EMS SQL Management Studio , но жалко она не помогла, часть запроса было отформатирована нормально, часть имела еще большей не читабельный текст



Очень давно пользуюсь прекрасным редактором notepad++, он красиво разукрашивает код, умеет выделять блоки. И у меня возникла идея поискать для него плагин для форматирования текста sql запроса. в общем то покопавшись в нете плагин был найден, вот только с текущей версией он не работал...



Очень жаль, но ребята которые разработали этот плагин, сделали страницу на которой можно отформатировать даже очень сложный скрипт sql.

Не отформатированный скрипт




итоговый красивый скрипт



Блогадаря этой странице, достаточно быстро разобрался в запутанном скрипте и исправил ошибку.


Friday, February 22, 2013

1С СКД Проблемы при программной работе с настройкой компоновщика настроек

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

КомпоновщикНастроек.Инициализировать(Отчеты[НазваниеОтчета].ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных"));
КомпоновщикНастроек.ЗагрузитьНастройки(Отчеты[НазваниеОтчета].ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных").ВариантыНастроек[ВаринтНастроек].Настройки);

Не знаю, что думал в 1С, но порывшись в нете нашел правильную схему формирования настроек

АдресСКД = ПоместитьВоВременноеХранилище(Отчеты[НазваниеОтчета].ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных"), ЭтаФорма.УникальныйИдентификатор);
ИсточникДоступныхНастроек = Новый ИсточникДоступныхНастроекКомпоновкиДанных(АдресСКД);

КомпоновщикНастроек.Инициализировать(ИсточникДоступныхНастроек);
КомпоновщикНастроек.ЗагрузитьНастройки(Отчеты[НазваниеОтчета].ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных").ВариантыНастроек[ВаринтНастроек].Настройки);

Monday, February 11, 2013

Формирование отчета с использованием СКД и внешних наборов данных

Очень странно, но единой схемы в интернете по работе в системе компоновки данных я не нашел и на вылетающие ошибки пришлось потратить время, а так имеем задачу соединить остатки 2 разных баз "Управленческой" и бухгалтерской. Так как синхронизация в базах выполняется регулярно имеем одинаковые уникальные идентификаторы.
Начинаем
1. Создаем внешний отчет



1.1. В "наборы данных" добавляем "Набор данных - объединение"
1.2. В созданный набор добавляем "Набор данных - запрос" И формируем необходимый нам запрос с помощью конструктора.
1.3. В набор объединение добавляем также "Набор данных - объект" и прописываем поля которые будут загружены с таблицызначений, не забываем что поля должны совпадать с полями из набора данных запрос

2. После этого переходим в модуль объекта, и добавляем стандартную процедуру "ПриКомпоновкеРезультата". 1С автоматически генерирует процедуру со всеми входящими параметрами. И начинаем формировать заполнение процедуры



Exported from Notepad++




Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
// При формирование отключаем стандартную обработку, в противном случае постоянно будет выдавать следующую ошибку
// Ошибка исполнения отчета
//по причине:
//Ошибка инициализации
//по причине:
//Ошибка создания набора данных "НаборДанных"
//по причине:
//Не найден внешний набор данных "ТаблОст"

СтандартнаяОбработка = Ложь;


//Формируем подключение к внешней базе 1с
Подкл = Новый COMОбъект("V82.COMConnector");
COMОбъект = Подкл.Connect("Srvr=""mws-01"";Ref=""GlobalBase"";Usr=""*****"";Pwd=""******""");

//Формируем запрос во внешней базе

Запрос = COMОбъект.NewObject("Запрос");

Запрос.Текст = "ВЫБРАТЬ
| ТоварыНаСкладахОстатки.Номенклатура,
| ТоварыНаСкладахОстатки.ВНаличииОстаток КАК КоличествоОстаток,
| ТоварыНаСкладахОстатки.ВРезервеОстаток КАК ВРезерве
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки
|ГДЕ
| ТоварыНаСкладахОстатки.Склад В
| (ВЫБРАТЬ
| Склады.Ссылка
| ИЗ
| Справочник.Склады КАК Склады
| ГДЕ
| Склады.Родитель.Наименование = ""Центральные Склады"")"
;



Результат = Запрос.Выполнить();
//Получаем результат и создаем и заполняем таблицу значений в текущей
ТаблОст = Новый ТаблицаЗначений;
ТаблОст.Колонки.Добавить("Номенклатура",новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
ТаблОст.Колонки.Добавить("Организация",ОбщегоНазначения.ПолучитьОписаниеТиповСтроки(10));
ТаблОст.Колонки.Добавить("КоличествоОстаток", ОбщегоНазначения.ПолучитьОписаниеТиповЧисла(15,3));
ТаблОст.Колонки.Добавить("СуммаОстаток", ОбщегоНазначения.ПолучитьОписаниеТиповЧисла(15,2));
Табл = Результат.Выгрузить();
Для х=0 по Табл.Количество()-1 Цикл
ЗначСтр = Табл.Получить(х);
НоваяСтрока = ТаблОст.Добавить();
//По уникальному идентификатору получаем значение и преобразуем в ссылку в текущей базе
НоваяСтрока.Номенклатура = Справочники.Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор(COMОбъект.String(ЗначСтр.Номенклатура.УникальныйИдентификатор())));
НоваяСтрока.Организация = "Упр"; // формируем левое название, так как управленческой базы нет в бухгалтерии
НоваяСтрока.СуммаОстаток = 0;
НоваяСтрока.КоличествоОстаток = Число(ЗначСтр.КоличествоОстаток);
КонецЦикла;
COMОбъект = неопределено;
Подкл = неопределено;


ВнешниеНаборыДанных = Новый Структура;
ВнешниеНаборыДанных.Вставить("ТаблОст",ТаблОст); // Формируем структуру для передечи в СКД


КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;

НастройкиКомпоновкиДанных = КомпоновщикНастроек.ПолучитьНастройки();

ТекСхема = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");

МакетКомпоновки = КомпоновщикМакета.Выполнить(
ТекСхема,
НастройкиКомпоновкиДанных,
ДанныеРасшифровки
);

ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(
МакетКомпоновки,
ВнешниеНаборыДанных,
ДанныеРасшифровки
);

ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.НачатьВывод();
ПроцессорВывода.Вывести(ПроцессорКомпоновки, Истина);
ПроцессорВывода.ЗакончитьВывод();

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



3. Далее, заполняем настройки, ресурсы и параметры

Как итог получаем отчет с нужными данными





Friday, February 8, 2013

Функция формирования навигационной ссылки для внешнего соединения 1С 8.2 Управляемые формы

У меня возникла ситуация, при рассылки сообщений при изменений статусов документов, через почту, с необходимостью указывать ссылку на документ, так как в работе используем 1С управляемые формы, до хватало ссылки на активацию через браузер, внизу сама функция формирования ссылки:



Exported from Notepad++




Функция ВернутьНавигационнуюСсылку(СсылкаНаОбъект) Экспорт
Возврат "http://ТутУказываетсяАдресСервера/ТутНазваниеБазы/#"+СтрЗаменить(ПолучитьНавигационнуюСсылку(СсылкаНаОбъект),"""","%22");
КонецФункции

Рассылка СКД отчетов из 1С с помощью фоновых заданий.

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

1. И самое основное для создания рассылки необходимо создать фоновое задание и процедуру формирования рассылки. Для этого я создал общий модуль "ПочтовыеРассылки" и установил в свойствах что он является "Серверным" и свойствах "Вызов сервера=Истина" + "Привилегированный=Истина".
Далее в него добавил 2 процедуры:

С процедурой отправить, думаю все понятно.


Exported from Notepad++



//Требование к запуску процедуры
//1.ДанныеПисьма = Структура
//1.1 ДанныеПисьма.Кому = массив адресат
//1.2 ДанныеПисьма.Вложения = массив строчный на файлы для вложения
//1.3 ДанныеПисьма.Тема - Тема письма
//1.4 Тело
//1.5 ОбратныйАдрес
//ДанныеПисьма = Новый Структура("Тема,Тело,Кому,Вложения");

Процедура Отправить(ДанныеПисьма) экспорт
//для получения доступа к набору свойств для соединения с сервером
//создадим новый объект
УстановитьПривилегированныйРежим(Истина);
Профиль = Новый ИнтернетПочтовыйПрофиль;

//Пропишем параметры соединения
//ip адрес или имя SMTP сервера
Профиль.АдресСервераSMTP = "*********";

//Порт SMTP сервера
Профиль.ПортSMTP = "***";

//Имя пользователя почтового ящика
Профиль.Пользователь = "***********";

//Пароль доступа к почтовому ящику
Профиль.Пароль = "******************";

//При необходимости добавляем аутентификацию
Профиль.АутентификацияSMTP = СпособSMTPАутентификации.БезАутентификации;
//Профиль.ПарольSMTP = Профиль.Пароль;
//Профиль.ПользовательSMTP = Профиль.Пользователь;
// Создаем объект для работы с почтой
Почта = Новый ИнтернетПочта;

//Выполняем подключение, согласно указанный параметров
Попытка
Почта.Подключиться(Профиль);
Исключение
//При подключении возникла ошибка, сообщим
Сообщить("Ошибка при подключении к серверу" + ОписаниеОшибки());
Возврат;
КонецПопытки;

//Создаем новое письмо (сообщение)
Сообщение = Новый ИнтернетПочтовоеСообщение;
Если ДанныеПисьма.Свойство("ОбратныйАдрес") И ТипЗнч(ДанныеПисьма.ОбратныйАдрес)= Тип("Строка") тогда
Сообщение.ОбратныйАдрес.Добавить(ДанныеПисьма.ОбратныйАдрес);
Сообщение.Отправитель = ДанныеПисьма.ОбратныйАдрес;
КонецЕсли;

//Указываем отправителя
//Сообщение.Отправитель = "*********@*****";

Если ТипЗнч(ДанныеПисьма.Кому)= Тип("Строка") тогда
Сообщение.Получатели.Добавить(ДанныеПисьма.Кому);
ИначеЕсли ТипЗнч(ДанныеПисьма.Кому) = Тип("Массив") тогда
Для Каждого ЗначКому из ДанныеПисьма.Кому Цикл
Сообщение.Получатели.Добавить(ЗначКому);
КонецЦикла;
Иначе
//Если какая-то жопа то шлем мне
Сообщение.Получатели.Добавить("********@******");
КонецЕсли;


//Пишем тему письма
Сообщение.Тема = ДанныеПисьма.Тема;

//Формируем текст письма,указываем тип письма
Сообщение.Тексты.Добавить(ДанныеПисьма.Тело,ТипТекстаПочтовогоСообщения.HTML);

//При необходимости делаем вложение с файлом
Если ДанныеПисьма.Свойство("Вложения") тогда
Если ТипЗнч(ДанныеПисьма.Вложения)= Тип("Строка") тогда
Сообщение.Вложения.Добавить(ДанныеПисьма.Вложения);
ИначеЕсли ТипЗнч(ДанныеПисьма.Вложения) = Тип("Массив") тогда
Для Каждого Файл из ДанныеПисьма.Вложения Цикл
Сообщение.Вложения.Добавить(Файл);
КонецЦикла;
КонецЕсли;
КонецЕсли;

//Непосредственно отправка сообщения
Почта.Послать(Сообщение);

//После отправки закрываем соединение
Почта.Отключиться();
Сообщение = Неопределено;
Почта = Неопределено;
УстановитьПривилегированныйРежим(Ложь);
КонецПроцедуры



// Передаем
//1. СхемаКомпоновкиДанных
//2. КомпоновщикНастроекКомпоновкиДанных
//3. СтрктуруПисьма - см. процедуру Отправить
//4. СтруктуруФайла отправки
//4.1. Файлом = Истина (если доп. вложением) Если ложь то html4 и вставляем в тело письма
//4.2 Типом файла

Процедура СформироватьИОтправитьОтчетПоПочте(СтруктураФормирования) Экспорт

УстановитьПривилегированныйРежим(Истина);
СхемаКомпоновкиДанных=СтруктураФормирования.СхемаКомпоновкиДанных;
//Настройки=СхемаКомпоновкиДанных.НастройкиПоУмолчанию;
//Если СтруктураНастроек=Неопределено тогда
// КомпоновщикНастроекКомпоновкиДанных = СтруктураФормирования.КомпоновщикНастроекКомпоновкиДанных;
//Иначе
// КомпоновщикНастроекКомпоновкиДанных = СтруктураНастроек.КомпоновщикНастроекКомпоновкиДанных;
//КонецЕсли;


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

ТемпФайл=ПолучитьИмяВременногоФайла(Строка(СтруктураФормирования.СтруктураФайла.ТипФайлаТабличногоДокумента));

//ТабДок.Записать(ТемпФайл,ТипФайлаТабличногоДокумента.HTML4);
ТабДок.Записать(ТемпФайл,СтруктураФормирования.СтруктураФайла.ТипФайлаТабличногоДокумента);
Если СтруктураФормирования.СтруктураФайла.Файлом тогда
СтруктураФормирования.СтрктуруПисьма.Вставить("Вложения",ТемпФайл);
Иначе
Текст = Новый ЧтениеТекста(ТемпФайл);
СтруктураФормирования.СтруктураПисьма.Вставить("Тело",Текст.Прочитать());
Текст = Неопределено;
КонецЕсли;

//Требование к запуску процедуры
//1.ДанныеПисьма = Структура
//1.1 ДанныеПисьма.Кому = массив адресат
//1.2 ДанныеПисьма.Вложения = массив строчный на файлы для вложения
//1.3 ДанныеПисьма.Тема - Тема письма
//1.4 Тело
//1.5 ОбратныйАдрес
//ДанныеПисьма = Новый Структура("Тема,Тело,Кому,Вложения");

//Отправить(ДанныеПисьма)

ПочтовыеРассылки.Отправить(СтруктураФормирования.СтруктураПисьма);
УстановитьПривилегированныйРежим(Ложь);
КонецПроцедуры




А вот вторую процедуру опишу более подробно.
Процедура "СформироватьИОтправитьОтчетПоПочте" получает на входе в структуре следующие значения
1. СхемаКомпоновкиДанных - Схему компоновки данных СКД
2. КомпоновщикНастроекКомпоновкиДанныхНастройки - Настройки схемы компоновки данных, пробывал передавать компоновщик настроек, но по непонятным причинам при выполнении на сервере в структуру вместо компоновщика, передавалась схема. Поигравшись с разными вариантами, стал передавать только настройки, так как сам компоновщик мне и не нужен.
3. СтруктураФайла - в этой структуре я описываю, информацию по вложениям
3.1. СтруктураФайла.ТипФайлаТабличногоДокумента - Передается значение ТипФайлаТабличногоДокумента, если же формируем отчет в теле письма то передаем html4.
3.2. СтруктураФормирования.СтруктураФайла.Файлом - Булево, если значение = Истина, тогда файл передается вложением, если = Ложь - тогда в теле письма.
3.3. СтруктураФормирования.СтруктураПисьма - Передается структура для отправки.

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



Exported from Notepad++



Процедура ВыполнитьНаСервереТестовоеСоздание()
Обработка = ВнешниеОтчеты.Создать("c:\Work\UT11\МаркетинговыйОтчет.erf");



СтруктураРаботы = Новый структура;
СхемаКомпоновкиДанных=Обработка.СхемаКомпоновкиДанных;
СтруктураРаботы.Вставить("СхемаКомпоновкиДанных",СхемаКомпоновкиДанных);


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




КомпоновщикНастроекКомпоновкиДанных.ЗагрузитьНастройки(СхемаКомпоновкиДанных.ВариантыНастроек.Основной.Настройки);
КомпоновщикНастроекКомпоновкиДанных.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(СхемаКомпоновкиДанных));



КомпоновщикНастроекКомпоновкиДанных.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("НачалоПериода", НачалоДня(Дата(2013,02,05)));
КомпоновщикНастроекКомпоновкиДанных.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("КонецПериода", КонецДня(Дата(2013,03,29)));
КомпоновщикНастроекКомпоновкиДанных.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("Организация", Справочники.Организации.НайтиПоНаименованию("Опт"));
КомпоновщикНастроекКомпоновкиДанных.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("СегментНоменклатурыАкция", Справочники.СегментыНоменклатуры.НайтиПоНаименованию("Акция"));
КомпоновщикНастроекКомпоновкиДанных.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("СегментПартнеровАкция", Справочники.СегментыПартнеров.НайтиПоНаименованию("Рабочие"));



СтруктураРаботы.Вставить("КомпоновщикНастроекКомпоновкиДанных",КомпоновщикНастроекКомпоновкиДанных);

СтруктураФайла = Новый Структура;
СтруктураФайла.Вставить("Файлом",Ложь);
СтруктураФайла.Вставить("ТипФайлаТабличногоДокумента",ТипФайлаТабличногоДокумента.HTML4);
СтруктураРаботы.Вставить("СтруктураФайла",СтруктураФайла);

СтруктураПисьма = Новый Структура;
СтруктураПисьма.Вставить("Кому","*****@*********");
СтруктураПисьма.Вставить("Тема","Акция SOX");
//Новый Структура("Кому,Тема,Тело","********@********","График оплат",СтрHTML)
СтруктураРаботы.Вставить("СтруктураПисьма",СтруктураПисьма);
СтруктураРаботы.Вставить("КомпоновщикНастроекКомпоновкиДанныхНастройки",КомпоновщикНастроекКомпоновкиДанных.Настройки);
//ПочтовыеРассылки.СформироватьИОтправитьОтчетПоПочте(СтруктураРаботы);

Задание = РегламентныеЗадания.СоздатьРегламентноеЗадание(Метаданные.РегламентныеЗадания.ПочтовыеРассылкиОтчетов);
Задание.Использование = Ложь;
Задание.Наименование = "Почтовая рассылка Акция";

ПараметрыЗадания = Новый Массив;
ПараметрыЗадания.Добавить(СтруктураРаботы);
ПараметрыЗадания.Добавить(Новый Структура("КомпоновщикНастроекКомпоновкиДанных",КомпоновщикНастроекКомпоновкиДанных));
Задание.Параметры = ПараметрыЗадания;

Задание.Записать();



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


После создания фонового задания можно установить регламент, активировать в обработке по работе с фоновыми заданиями.

Monday, February 4, 2013

Формирование планов в Excel по данным из 1С 8.2 УТ11

Поступила от руководства интересная задача по формированию планов.
Фактически данную задачу можно было бы сформировать и в 1С, но манагеры люди гордые им удобнее работать в excel'е. В связи с этим и пришлось хорошенько помучиться, что бы все работало правильно.
Плюс ко всему из-за чего был выбран именно Excel, уточнение в задаче состояло что выбрать для формирования планов нужно было всю номенклатуру с группировкой до 2 уровня.
1. Проблемой которая возникла, использование excel на сервере, так как используем 1С 8.2 (x64) то на сервере в обязательном порядке должен быть установлен офис (x64).
2. Проблема состоит в том что необходимо разрешить использование DCOM, в противном случае не получиться инициализировать Excel.
3. Проблема состоялась в правах на чтение и запись от имени пользователя под которым запущен 1с.
4. Прикол excel необходимо создать каталог (без него excel отказывался записывать файл) c:\Windows\SysWOW64\config\systemprofile\Desktop\
5. C excel'ом пришлось подолбаться хорошо, благо часть задач помогло решить работа с макросами (формируем необходимый файл, после включаем запись макроса, выполняем необходимое действие руками, останавливаем макрос, и входим в него в режиме отладки), но с некоторыми было тяжеловато, пришлось перебирать кучу страниц из поиска в поисках оптимальных идей.

Ниже приведен код работы внешней обработки, основные 2 процедуры ВыгрузитьФайлик и ОформитьПлан.
1. Часть формируем запрос в 1с
2. Для скорости выгружаем данные через OLEDB
3. Открываем в excel и формируем Сводную таблицу (Pivot table)
4. Так как в сводную таблицу очень тяжело что либо вносить, копируем
5. Форматируем в необходимый вид
6. Добавляем две колонки по работе с планами и заполняем иерархию формулами
7. Далее уже от того, что необходимо, либо отсылаем по почте(за комментировано), либо отдаем пользователю


&НаКлиенте Процедура Команда1(Команда) СтруктФункц = Новый Структура(); СтруктФункц.Вставить("Подр", ЭтаФорма.Подразделение); СтруктФункц.Вставить("ПоказыватьСебестоимость", НЕ ЭтаФорма.ПоказыватьСебестоимость); СтруктФункц.Вставить("ДатаНачала",ЭтаФорма.ПериодОтчета.ДатаНачала); СтруктФункц.Вставить("ДатаОкончания",ЭтаФорма.ПериодОтчета.ДатаОкончания); СтруктФункц.Вставить("ФормаУИД",ЭтаФорма.УникальныйИдентификатор); Адрес = ВыгрузитьФайлик(СтруктФункц); ПолучитьФайл(Адрес,Transliterate(Подразделение)+".xlsx",Истина); КонецПроцедуры &НаСервереБезКонтекста Функция ВернутьТекстЗапроса() Возврат "ВЫБРАТЬ | Номенклатура.Ссылка КАК Ссылка, | Номенклатура.НаправленияДеятельности.Наименование КАК НаправленияДеятельности |ИЗ | Справочник.Номенклатура КАК Номенклатура |ГДЕ | Номенклатура.ЭтоГруппа | И Номенклатура.Ссылка В | (ВЫБРАТЬ | КлючиАналитикиУчетаНоменклатуры.Номенклатура.Родитель | ИЗ | РегистрНакопления.ВыручкаИСебестоимостьПродаж.Обороты(&ПериодНачала, &ПериодОкончания, , ) КАК ВыручкаИСебестоимостьПродажОбороты ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.КлючиАналитикиУчетаНоменклатуры КАК КлючиАналитикиУчетаНоменклатуры | ПО | ВыручкаИСебестоимостьПродажОбороты.АналитикаУчетаНоменклатуры = КлючиАналитикиУчетаНоменклатуры.Ссылка | СГРУППИРОВАТЬ ПО | КлючиАналитикиУчетаНоменклатуры.Номенклатура.Родитель) | |УПОРЯДОЧИТЬ ПО | Номенклатура.Ссылка ИЕРАРХИЯ |; | |//////////////////////////////////////////////////////////////////////////////// |ВЫБРАТЬ | ВыручкаИСебестоимостьПродажОбороты.Период КАК Период, | КлючиАналитикиУчетаПоПартнерам.Партнер.ОсновнойМенеджер.Наименование КАК Менеджер, | КлючиАналитикиУчетаПоПартнерам.Партнер.ОсновнойМенеджер.ТекущееПодразделение.Наименование + "" ("" + КлючиАналитикиУчетаПоПартнерам.Партнер.ОсновнойМенеджер.ТекущееПодразделение.Код + "")"" КАК Подразделение, | КлючиАналитикиУчетаПоПартнерам.Партнер.Наименование + "" ("" + КлючиАналитикиУчетаПоПартнерам.Партнер.Код + "")"" КАК Партнер, | СУММА(ВыручкаИСебестоимостьПродажОбороты.КоличествоОборот) КАК Количество, | СУММА(ВыручкаИСебестоимостьПродажОбороты.СуммаВыручкиОборот) КАК Выручка, | ВЫБОР | КОГДА &ПоказыватьСебестоимость | ТОГДА 0 | ИНАЧЕ СУММА(ВыручкаИСебестоимостьПродажОбороты.СебестоимостьОборот) | КОНЕЦ КАК Себестоимость, | ВЫБОР | КОГДА &ПоказыватьСебестоимость | ТОГДА 0 | ИНАЧЕ СУММА(ВыручкаИСебестоимостьПродажОбороты.СуммаДополнительныхРасходовОборот) | КОНЕЦ КАК ДопРасходы, | КлючиАналитикиУчетаНоменклатуры.Номенклатура.Родитель КАК Ссылка |ИЗ | РегистрНакопления.ВыручкаИСебестоимостьПродаж.Обороты( | &ПериодНачала, | &ПериодОкончания, | Месяц, | АналитикаУчетаПоПартнерам В | (ВЫБРАТЬ | КлючиАналитикиУчетаПоПартнерам.Ссылка | ИЗ | Справочник.КлючиАналитикиУчетаПоПартнерам КАК КлючиАналитикиУчетаПоПартнерам | ГДЕ | КлючиАналитикиУчетаПоПартнерам.Организация = &Организация | И КлючиАналитикиУчетаПоПартнерам.Партнер В | (ВЫБРАТЬ | ПартнерыСегмента.Партнер | ИЗ | РегистрСведений.ПартнерыСегмента КАК ПартнерыСегмента ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Партнеры КАК Партнеры ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Пользователи КАК Пользователи | ПО | Партнеры.ОсновнойМенеджер = Пользователи.Ссылка | ПО | ПартнерыСегмента.Партнер = Партнеры.Ссылка | ГДЕ | ПартнерыСегмента.Сегмент = &Сегмент | И НЕ Партнеры.ОсновнойМенеджер = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) | И Пользователи.ТекущееПодразделение В | (ВЫБРАТЬ | СтруктураПредприятия.Ссылка | ИЗ | Справочник.СтруктураПредприятия КАК СтруктураПредприятия | ГДЕ | СтруктураПредприятия.Ссылка В ИЕРАРХИИ (&Подразделение))))) КАК ВыручкаИСебестоимостьПродажОбороты | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.КлючиАналитикиУчетаНоменклатуры КАК КлючиАналитикиУчетаНоменклатуры | ПО ВыручкаИСебестоимостьПродажОбороты.АналитикаУчетаНоменклатуры = КлючиАналитикиУчетаНоменклатуры.Ссылка | ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.КлючиАналитикиУчетаПоПартнерам КАК КлючиАналитикиУчетаПоПартнерам | ПО ВыручкаИСебестоимостьПродажОбороты.АналитикаУчетаПоПартнерам = КлючиАналитикиУчетаПоПартнерам.Ссылка | |СГРУППИРОВАТЬ ПО | ВыручкаИСебестоимостьПродажОбороты.Период, | КлючиАналитикиУчетаПоПартнерам.Партнер.ОсновнойМенеджер.Наименование, | КлючиАналитикиУчетаНоменклатуры.Номенклатура.Родитель, | КлючиАналитикиУчетаПоПартнерам.Партнер.ОсновнойМенеджер.ТекущееПодразделение.Наименование + "" ("" + КлючиАналитикиУчетаПоПартнерам.Партнер.ОсновнойМенеджер.ТекущееПодразделение.Код + "")"", | КлючиАналитикиУчетаПоПартнерам.Партнер.Наименование + "" ("" + КлючиАналитикиУчетаПоПартнерам.Партнер.Код + "")"" | |УПОРЯДОЧИТЬ ПО | Ссылка, | Подразделение, | Менеджер, | Партнер |; | |//////////////////////////////////////////////////////////////////////////////// |ВЫБРАТЬ | Партнеры.Наименование + "" ("" + Партнеры.Код + "")"" КАК Партнер, | Партнеры.ОсновнойМенеджер.Наименование КАК Менеджер, | Партнеры.ОсновнойМенеджер.ТекущееПодразделение.Наименование + "" ("" + Партнеры.ОсновнойМенеджер.ТекущееПодразделение.Код + "")"" КАК Подразделение, | 0 КАК Количество, | 0 КАК Выручка, | 0 КАК Себестоимость, | 0 КАК ДопРасходы |ИЗ | Справочник.Партнеры КАК Партнеры | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Пользователи КАК Пользователи | ПО Партнеры.ОсновнойМенеджер = Пользователи.Ссылка |ГДЕ | Партнеры.Ссылка В | (ВЫБРАТЬ | ПартнерыСегмента.Партнер | ИЗ | РегистрСведений.ПартнерыСегмента КАК ПартнерыСегмента | ГДЕ | ПартнерыСегмента.Сегмент = &Сегмент) | И НЕ Партнеры.ОсновнойМенеджер = ЗНАЧЕНИЕ(Справочник.Пользователи.ПустаяСсылка) | И Пользователи.ТекущееПодразделение В | (ВЫБРАТЬ | СтруктураПредприятия.Ссылка | ИЗ | Справочник.СтруктураПредприятия КАК СтруктураПредприятия | ГДЕ | СтруктураПредприятия.Ссылка В ИЕРАРХИИ (&Подразделение))"; КонецФункции &НаСервереБезКонтекста Функция Transliterate(srtRusWord) Экспорт strRUS = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ"; strENG = "A///B///V///G///D///E///YO//ZH//Z///I///Y///K///L///M///N///O///P///R///S///T///U///F///KH//TS//CH//SH//SHCH'///Y///////E///YU//JA//"; strResult = ""; Для i = 1 по СтрДлина(srtRusWord) Цикл s = Сред(srtRusWord, i,1); s=ВРег(s); k = Найти(strRUS, s); Если k = 0 тогда strResult = strResult + s; Иначе strResult = strResult + СтрЗаменить(Сред(strENG, (k - 1) * 4 + 1, 4), "/", ""); КонецЕсли КонецЦикла ; Возврат СокрЛП(strResult); КонецФункции &НаСервереБезКонтекста Функция ПолучитьНазваниеДляВыгрузки(НРодитель) //Родитель = Справочники.Номенклатура.СоздатьГруппу(); Если НРодитель=null or НРодитель.Пустая() тогда Возврат ""; КонецЕсли; СтрокаВозврата = ""; Если Не НРодитель.КодСортировки=0 тогда СтрокаВозврата = СтрокаВозврата + Формат(НРодитель.КодСортировки,"ЧЦ=3; ЧДЦ=0; ЧН=0; ЧВН=; ЧГ=0")+". "; КонецЕсли; СтрокаВозврата = СтрокаВозврата + НРодитель.Наименование + " (" + НРодитель.Код+")"; return СтрокаВозврата; КонецФункции &НаСервере Функция ВыгрузитьФайлик(СтруктФункц) Экспорт ВремяНачала = ТекущаяДата(); //ИмяФайлаЭксель = "C:\1\"+Transliterate(Подр.Наименование)+".xlsx"; // Имя создаваемого файла ИмяФайлаЭксель1 = КаталогВременныхФайлов()+Transliterate(СтруктФункц.Подр.Наименование)+".xlsx"; // Имя создаваемого файла ИмяФайлаЭксель = КаталогВременныхФайлов()+Transliterate(СтруктФункц.Подр.Наименование)+"(1).xlsx"; // Имя создаваемого файла ИмяФайлаZIP = КаталогВременныхФайлов()+Transliterate(СтруктФункц.Подр.Наименование)+".zip"; // Имя создаваемого файла УдалитьФайлы(ИмяФайлаЭксель); // Собираем строку подключения Command = Неопределено; //Connection.Close(); Connection = Неопределено; Table = Неопределено; Catalog = Неопределено; СтрокаПодключения = " |Provider=Microsoft.ACE.OLEDB.12.0; |Data Source="+ИмяФайлаЭксель+"; |Extended Properties=""Excel 12.0 Xml;HDR=YES;"";"; // Создаем соединение Connection = Новый COMОбъект("ADODB.Connection"); Connection.Open(СтрокаПодключения); Command = Новый COMОбъект("ADODB.Command"); Command.ActiveConnection = Connection; Command.CommandType = 1; Command.CommandText = "CREATE TABLE [Table] |( |Родитель1 char(120) WITH Compression |,Родитель2 char(120) WITH Compression |,НаправленияДеятельности char(50) WITH Compression |,Период date |,ПериодМесяц char(7) |,ПериодГод int |,Подразделение char(50) WITH Compression |,Менеджер char(50) WITH Compression |,Партнер char(50) WITH Compression |,Количество float |,Отгрузка currency |,Себестоимость currency |,ДопРасходы currency);"; Command.Execute(); // Получаем номенклатуру для выгрузки Запрос = Новый Запрос(ВернутьТекстЗапроса()); ПериодНачала = НачалоДня(СтруктФункц.ДатаНачала); ПериодОкончания = КонецДня(СтруктФункц.ДатаОкончания); Запрос.УстановитьПараметр("ПериодНачала",ПериодНачала);//НачалоМесяца(ТекущаяДата())); Запрос.УстановитьПараметр("ПериодОкончания",ПериодОкончания); Запрос.УстановитьПараметр("Организация",Справочники.Организации.НайтиПоНаименованию("Опт")); Запрос.УстановитьПараметр("Подразделение",СтруктФункц.Подр); Запрос.УстановитьПараметр("ПоказыватьСебестоимость",СтруктФункц.ПоказыватьСебестоимость); Запрос.УстановитьПараметр("Сегмент",Справочники.СегментыПартнеров.НайтиПоНаименованию("Рабочие")); Результат = Запрос.ВыполнитьПакет(); Выборка1 = Результат[0].Выбрать(); //Номенклатура Выборка2 = Результат[1].Выбрать(ОбходРезультатазапроса.ПоГруппировкам); // ВыручкаИСебестоимостьПродаж ВыборкаОбщий = Результат[2].Выбрать(); // Полный ТаблНоменклатура = Результат[0].Выгрузить(); ТаблНоменклатура.Колонки.Добавить("Родитель1",Новый ОписаниеТипов("Строка",, Новый КвалификаторыСтроки(120))); ТаблНоменклатура.Колонки.Добавить("Родитель2",Новый ОписаниеТипов("Строка",, Новый КвалификаторыСтроки(120))); ТаблНоменклатура.Колонки.Добавить("Группа1",Новый ОписаниеТипов("СправочникСсылка.Номенклатура")); ТаблНоменклатура.Колонки.Добавить("Группа2",Новый ОписаниеТипов("СправочникСсылка.Номенклатура")); ТаблНоменклатура.Колонки.Добавить("Количество",Новый ОписаниеТипов("Число",, Новый КвалификаторыЧисла(12,2))); ТаблНоменклатура.Колонки.Добавить("Отгрузка",Новый ОписаниеТипов("Число",, Новый КвалификаторыЧисла(12,2))); ТаблНоменклатура.Колонки.Добавить("Себестоимость",Новый ОписаниеТипов("Число",, Новый КвалификаторыЧисла(12,2))); ТаблНоменклатура.Колонки.Добавить("ДопРасходы",Новый ОписаниеТипов("Число",, Новый КвалификаторыЧисла(12,2))); Для Каждого СтрокаНом Из ТаблНоменклатура Цикл СтруктураГрупп = ВернутьГруппы(СтрокаНом.Ссылка); СтрокаНом.Родитель1 = СтруктураГрупп.Группа1С; СтрокаНом.Родитель2 = СтруктураГрупп.Группа2С; СтрокаНом.Группа1 = СтруктураГрупп.Группа1О; СтрокаНом.Группа2 = СтруктураГрупп.Группа2О; КонецЦикла; ТаблНоменклатура.Свернуть("Родитель1,Группа1,Родитель2,Группа2","Количество,Отгрузка,Себестоимость,ДопРасходы"); ТаблПродажи = Результат[1].Выгрузить(); ТаблПродажи.Колонки.Добавить("Родитель1",Новый ОписаниеТипов("Строка",, Новый КвалификаторыСтроки(120))); ТаблПродажи.Колонки.Добавить("Родитель2",Новый ОписаниеТипов("Строка",, Новый КвалификаторыСтроки(120))); ТаблПродажи.Колонки.Добавить("Группа1",Новый ОписаниеТипов("СправочникСсылка.Номенклатура")); ТаблПродажи.Колонки.Добавить("Группа2",Новый ОписаниеТипов("СправочникСсылка.Номенклатура")); Для Каждого СтрокаПродаж Из ТаблПродажи Цикл СтруктураГрупп = ВернутьГруппы(СтрокаПродаж.Ссылка); СтрокаПродаж.Родитель1 = СтруктураГрупп.Группа1С; СтрокаПродаж.Родитель2 = СтруктураГрупп.Группа2С; СтрокаПродаж.Группа1 = СтруктураГрупп.Группа1О; СтрокаПродаж.Группа2 = СтруктураГрупп.Группа2О; КонецЦикла; ТаблПродажи.Свернуть("Период,Менеджер,Подразделение,Партнер,Родитель1,Группа1,Родитель2,Группа2","Количество,Выручка,Себестоимость,ДопРасходы"); ПериодОкончанияНД = НачалоМесяца(ПериодОкончания); // Заполняем таблицу данными выборки Для Каждого СтрокаНом Из ТаблНоменклатура Цикл ВыборкаОбщий.Сбросить(); Пока ВыборкаОбщий.Следующий() Цикл Выборка= СоздатьСтруктуру(); ЗаполнитьЗначенияСвойств(Выборка,СтрокаНом); ЗаполнитьЗначенияСвойств(Выборка,ВыборкаОбщий); Выборка.Период = ПериодОкончанияНД;//ПериодНачала; Command.CommandText = СформироватьСтрокуЗапроса(Выборка); Command.Execute(); КонецЦикла; Для каждого НайденаяСтрока из ТаблПродажи.НайтиСтроки(Новый Структура("Группа1,Группа2",СтрокаНом.Группа1,СтрокаНом.Группа2)) Цикл Выборка= СоздатьСтруктуру(); ЗаполнитьЗначенияСвойств(Выборка,СтрокаНом); ЗаполнитьЗначенияСвойств(Выборка,НайденаяСтрока); Command.CommandText = СформироватьСтрокуЗапроса(Выборка); Command.Execute(); КонецЦикла; КонецЦикла; ВремяОкончания = ТекущаяДата(); Сообщить("Время начала:"+ВремяНачала); Сообщить("Время окончания:"+ВремяОкончания); // Закрываем соединение Command = Неопределено; Connection.Close(); Connection = Неопределено; Excel = новый COMОбъект("Excel.Application"); Excel.DisplayAlerts=0; Excel.Visible = 0; Excel.ScreenUpdating = False; Excel.EnableEvents = False; Книга = Excel.Workbooks.Open(ИмяФайлаЭксель); ОформитьПлан(Excel, Книга); Книга.Save(); Excel.Workbooks.Close(); Excel.Quit(); Excel=Неопределено; // СписокРассылки = Новый СписокЗначений; // СписокРассылки.Добавить("dyachok.n"); // // ФайлZip = Новый ЗаписьZipФайла(ИмяФайлаZIP,, "Выгрузка отгрузок", МетодСжатияZIP.Сжатие, УровеньСжатияZIP.Максимальный); // ФайлZip.Добавить(ИмяФайлаЭксель,РежимСохраненияПутейZIP.НеСохранятьПути,РежимОбработкиПодкаталоговZIP.НеОбрабатывать); // ФайлZip.Записать(); // ФайлZip = Неопределено; // // Мас = Новый Массив; // //ИмяФайлаНью = КаталогВременныхФайлов()+ИмяФайлаЭксель; // // Мас.Добавить(ИмяФайлаZIP); // // // //ИмяФайла = КаталогВременныхФайлов()+"Price_"+Формат(ДатаФормированияПрайса,"ДФ=yyyy-MM-dd")+".xls"; // //Мас.Добавить(ИмяФайла); // //ВыгрузитьВXLS(ИмяФайла); // ДанныеПисьма = Новый Структура("Тема,Тело","Информация по отгрузке:"+Подр,"Данные выгружены за период с "+Формат(ДатаНачала,"ДФ=dd.MM.yyyy")+" по "+Формат(ДатаОкончания,"ДФ=dd.MM.yyyy")); // Отправить(ДанныеПисьма,Мас,СписокРассылки); // УдалитьТемпФайл(ИмяФайлаZIP); // УдалитьТемпФайл(ИмяФайлаЭксель); // УдалитьТемпФайл(ИмяФайлаЭксель1); Адрес = ПоместитьВоВременноеХранилище(Новый ДвоичныеДанные(ИмяФайлаЭксель),СтруктФункц.ФормаУИД); Возврат Адрес; КонецФункции &НаСервереБезКонтекста Функция rgb(r,g,b) Возврат r+g*256+b*65536; КонецФункции &НаСервереБезКонтекста Функция ФЕ(ЧислоЗнч) Возврат Формат(ЧислоЗнч,"ЧЦ=10; ЧДЦ=0; ЧГ=0"); КонецФункции //http://www.tayloredmktg.com/rgb/ - цвета &НаСервереБезКонтекста Процедура ОформитьПлан(Знач Excel, Знач Книга) Лист = Книга.WorkSheets("Table"); Лист.Select(); ВсегоКолонок = Лист.Cells(1,1).SpecialCells(11).Column; ВсегоСтрок = Лист.Cells(1,1).SpecialCells(11).Row; Лист.Activate(); дДиапазонДанных=Лист.UsedRange.Address; ДиапазонДанных=Лист.Name+"!"+Строка(дДиапазонДанных); xlDatabase = 1; SourceType = xlDatabase; SourceData = ДиапазонДанных; TableDestination=""; TableName="Plan"; ЛистА = Книга.Sheets.Add(,Excel.Sheets("Table")); Е = Excel.ActiveWorkbook.PivotCaches().Create(xlDatabase, ДиапазонДанных, 4); СВТ = Е.CreatePivotTable(ЛистА.Name+"!R3C1", TableName, 4); СВТ.SubtotalLocation(1); СВТ.RowAxisLayout(2); СВТ.TableStyle2 = "PivotStyleMedium2"; СВТПодразделение = СВТ.PivotFields("Подразделение"); СВТПодразделение.Orientation = 1; СВТПодразделение.Position = 1; СВТМенеджер = СВТ.PivotFields("Менеджер"); СВТМенеджер.Orientation = 1; СВТМенеджер.Position = 2; СВТПартнер = СВТ.PivotFields("Партнер"); СВТПартнер.Orientation = 1; СВТПартнер.Position = 3; СВТРодитель1 = СВТ.PivotFields("Родитель1"); СВТРодитель1.Orientation = 1; СВТРодитель1.Position = 4; СВТРодитель2 = СВТ.PivotFields("Родитель2"); СВТРодитель2.Orientation = 1; СВТРодитель2.Position = 5; СВТПериодМесяц = СВТ.PivotFields("ПериодМесяц"); СВТПериодМесяц.Orientation = 2; СВТПериодМесяц.Position = 1; СВТ.AddDataField(СВТ.PivotFields("Количество"),"(Кол-во)",-4157); СВТ.AddDataField(СВТ.PivotFields("Отгрузка"),"(Отгрузка)",-4157); ВсегоКолонок1 = ЛистА.Cells(1,1).SpecialCells(11).Column; ВсегоСтрок1 = ЛистА.Cells(1,1).SpecialCells(11).Row; ЛистА.Activate(); Книга.ActiveSheet.Name = "План1"; дДиапазонДанных=ЛистА.UsedRange.Address; ДиапазонДанных=ЛистА.Name+"!"+Строка(дДиапазонДанных); Excel.Range(ДиапазонДанных).copy(); ЛистИ = Книга.Sheets.Add(,Excel.Sheets("План1")); ЛистИ.Name = "План"; ЛистИ.Select(); ЛистИ.Range("A1").Select(); Excel.Range("План!A1").PasteSpecial(-4163,-4142,false,false); Excel.Sheets("План1"). delete(); Excel.Sheets("Table").delete(); ЛистИ.Outline.SummaryRow = 0; // группировка сверху ВсегоКолонок = ЛистИ.Cells(1,1).SpecialCells(11).Column; ВсегоСтрок = ЛистИ.Cells(1,1).SpecialCells(11).Row; //Дальше формируем группировку ОбщСтр = Новый Структура; Для х=1 по 4 Цикл ОбщСтр.Вставить("Гр"+ФЕ(х),Новый Структура("ТекЗнач,НачЗнач,НачСтрока")); КонецЦикла; RangeCopy = ЛистИ.Range("$"+КЕ(6)+"$"+ФЕ(1)+":$"+КЕ(6+1)+"$"+ФЕ(ВсегоСтрок)); RangeCopy.Insert(-4161,0); Range = ЛистИ.Range("$"+КЕ(6)+"$"+ФЕ(1)+":$"+КЕ(6+1)+"$"+ФЕ(ВсегоСтрок)); Range.Interior.Color = rgb(135,206,250); Range.Borders(1).Weight = 2; Range.Borders(2).Weight = 2; Range.Borders(3).Weight = 2; Range.Borders(4).Weight = 2; RangePlan = ЛистИ.Range("$"+КЕ(6)+"$"+ФЕ(1)+":$"+КЕ(6+1)+"$"+ФЕ(1)); RangePlan.Merge(); RangePlan.Value="План"; Range = ЛистИ.Range("$"+КЕ(6)+"$"+ФЕ(2)+":$"+КЕ(6+1)+"$"+ФЕ(2)); Range.Merge(); ЛистИ.Cells(3, 6).Value = "(Кол-во)"; ЛистИ.Cells(3, 7).Value ="(Отгрузка)"; Range = ЛистИ.Range("$A$1:$"+КЕ(ВсегоКолонок+2)+"$3"); Range.Font.Name = "Arial Narrow"; Range.Font.Size = 12; Range.HorizontalAlignment =3; Range.VerticalAlignment =2; Range.Borders(1).Weight = 2; Range.Borders(2).Weight = 2; Range.Borders(3).Weight = 2; Range.Borders(4).Weight = 2; Range.Interior.Color = rgb(54,96,146); Range.Font.Color = rgb(255,255,255); Для СуммКол = 6 по ВсегоКолонок Цикл Если СуммКол%2 тогда ЛистИ.Columns(СуммКол).NumberFormat ="# ##0,00"; Иначе ЛистИ.Columns(СуммКол).NumberFormat ="# ##0"; Если НЕ СуммКол+2>ВсегоКолонок тогда Range = ЛистИ.Range("$"+КЕ(СуммКол)+"$"+ФЕ(2)+":$"+КЕ(СуммКол+1)+"$"+ФЕ(2)); Range.Merge(); КонецЕсли; КонецЕсли; КонецЦикла; Для СуммКол = ВсегоКолонок по ВсегоКолонок+2 Цикл // Для итогов не объединяем. Если СуммКол%2 тогда ЛистИ.Columns(СуммКол).NumberFormat ="# ##0,00"; Иначе ЛистИ.Columns(СуммКол).NumberFormat ="# ##0"; КонецЕсли; КонецЦикла; ВсегоКолонок = ВсегоКолонок+2; Для СтрокаЕ=4 по ВсегоСтрок Цикл Для х=1 по 4 Цикл ОбщСтр["Гр"+х].ТекЗнач = ЛистИ.Cells(СтрокаЕ, х).Value; Если (Не ПустаяСтрока(ОбщСтр["Гр"+х].ТекЗнач) И ОбщСтр["Гр"+х].ТекЗнач<>ОбщСтр["Гр"+х].НачЗнач) тогда Если НЕ ОбщСтр["Гр"+х].НачЗнач=НЕопределено тогда ЛистИ.Range("A"+ФЕ(ОбщСтр["Гр"+х].НачСтрока+1)+":"+КЕ(х)+ФЕ(СтрокаЕ-1)).Rows.Group(); Для у=х+1 по 4 Цикл ЛистИ.Range("A"+ФЕ(ОбщСтр["Гр"+у].НачСтрока+1)+":"+КЕ(у)+ФЕ(СтрокаЕ-1)).Rows.Group(); Для СуммКол = 6 по 8 Цикл ЛистИ.Cells(ОбщСтр["Гр"+у].НачСтрока, СуммКол).FormulaR1C1 = "=SUMIF(R[1]C["+ФЕ(5-СуммКол)+"]:R["+ФЕ(СтрокаЕ-ОбщСтр["Гр"+у].НачСтрока-1)+"]C["+ФЕ(5-СуммКол)+"],""*"",R[1]C:R["+ФЕ(СтрокаЕ-ОбщСтр["Гр"+у].НачСтрока-1)+"]C)"; КонецЦикла; ОбщСтр["Гр"+у].НачЗнач = Неопределено; ОбщСтр["Гр"+у].НачСтрока = СтрокаЕ-1; КонецЦикла; Для СуммКол = 6 по 8 Цикл ЛистИ.Cells(ОбщСтр["Гр"+х].НачСтрока, СуммКол).FormulaR1C1 = "=SUMIF(R[1]C["+ФЕ(5-СуммКол)+"]:R["+ФЕ(СтрокаЕ-ОбщСтр["Гр"+х].НачСтрока-1)+"]C["+ФЕ(5-СуммКол)+"],""*"",R[1]C:R["+ФЕ(СтрокаЕ-ОбщСтр["Гр"+х].НачСтрока-1)+"]C)"; КонецЦикла; КонецЕсли; ОбщСтр["Гр"+х].НачСтрока = СтрокаЕ; ОбщСтр["Гр"+х].НачЗнач = ОбщСтр["Гр"+х].ТекЗнач; Range = ЛистИ.Range("$"+КЕ(х)+"$"+ФЕ(СтрокаЕ)+":$"+КЕ(ВсегоКолонок)+"$"+ФЕ(СтрокаЕ)); Range.Font.Size = 16-х; Range.Interior.Color = rgb(255,255,255-(х*10)); ИначеЕсли НЕ ПустаяСтрока(ОбщСтр["Гр"+х].НачЗнач) тогда //ЛистИ.Cells(СтрокаЕ, х).Value = ОбщСтр["Гр"+х].НачЗнач; //ЛистИ.Cells(СтрокаЕ, х).Font.Color= rgb(255,255,255); КонецЕсли; КонецЦикла; КонецЦикла; ЛистИ.Cells.EntireColumn.AutoFit(); КонецПроцедуры &НаСервереБезКонтекста Функция КЕ(Номерколонки) // преобразуем число в колонку excel Дивиденд = Номерколонки; Модуль=0; СтрВозврата=""; Пока Дивиденд > 0 Цикл Модуль = (Дивиденд-1) % 26; Симв = Символ(65+Модуль); СтрВозврата = Симв+СтрВозврата; Дивиденд = Окр((Дивиденд - Модуль) / 26); КонецЦикла; Возврат СтрВозврата; КонецФункции &НаСервереБезКонтекста Функция СоздатьСтруктуру() Возврат Новый Структура("Код |,Наименование |,Родитель1 |,Родитель2 |,Родитель3 |,Родитель4 |,НаправленияДеятельности |,Период |,Подразделение |,Менеджер |,Партнер |,Количество |,Выручка |,Себестоимость |,ДопРасходы"); КонецФункции &НаСервереБезКонтекста Функция СформироватьСтрокуЗапроса(СтруктураВыборки) Возврат "INSERT INTO [Table] VALUES (" +"'"+СтрЗаменить(СтруктураВыборки.Родитель1,"'","''")+"'" +",'"+СтрЗаменить(СтруктураВыборки.Родитель2,"'","''")+"'" +",'"+СтрЗаменить(СтруктураВыборки.НаправленияДеятельности,"'","''")+"'" +",'"+СтрЗаменить(Формат(СтруктураВыборки.Период,"ДФ=MM/dd/yyyy"),"'","''")+"'" +",'"+СтрЗаменить(Формат(СтруктураВыборки.Период,"ДФ=MM.yyyy"),"'","''")+"'" +","+Формат(СтруктураВыборки.Период,"ДФ=yyyy")+"" +",'"+СтрЗаменить(СтруктураВыборки.Подразделение,"'","''")+"'" +",'"+СтрЗаменить(СтруктураВыборки.Менеджер,"'","''")+"'" +",'"+СтрЗаменить(СтруктураВыборки.Партнер,"'","''")+"'" +","+Формат(СтруктураВыборки.Количество,"ЧЦ=12; ЧДЦ=0; ЧРД=.; ЧН=0; ЧГ=0")+"" +","+Формат(СтруктураВыборки.Выручка,"ЧЦ=12; ЧДЦ=2; ЧРД=.; ЧН=0; ЧГ=0")+"" +","+Формат(СтруктураВыборки.Себестоимость,"ЧЦ=12; ЧДЦ=2; ЧРД=.; ЧН=0; ЧГ=0")+"" +","+Формат(СтруктураВыборки.ДопРасходы,"ЧЦ=12; ЧДЦ=2; ЧРД=.; ЧН=0; ЧГ=0")+"" +");"; КонецФункции &НаКлиенте Процедура ПриОткрытии(Отказ) КонецПроцедуры &НаСервере Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) ЭтаФорма.Подразделение = Справочники.СтруктураПредприятия.НайтиПоНаименованию("Опт"); ЭтаФорма.ПериодОтчета.Вариант=ВариантСтандартногоПериода.ПрошлыйКвартал; КонецПроцедуры Процедура Отправить(ДанныеПисьма,Вложения,Знач Кому) экспорт //для получения доступа к набору свойств для соединения с сервером //создадим новый объект Профиль = Новый ИнтернетПочтовыйПрофиль; //Пропишем параметры соединения //ip адрес или имя SMTP сервера Профиль.АдресСервераSMTP = "*********"; //Порт SMTP сервера Профиль.ПортSMTP = "25"; //Имя пользователя почтового ящика Профиль.Пользователь = "user********"; //Пароль доступа к почтовому ящику Профиль.Пароль = "*****************"; //При необходимости добавляем аутентификацию Профиль.АутентификацияSMTP = СпособSMTPАутентификации.Login; Профиль.ПарольSMTP = Профиль.Пароль; Профиль.ПользовательSMTP = Профиль.Пользователь; // Создаем объект для работы с почтой Почта = Новый ИнтернетПочта; //Выполняем подключение, согласно указанный параметров Попытка Почта.Подключиться(Профиль); Исключение //При подключении возникла ошибка, сообщим Сообщить("Ошибка при подключении к серверу" + ОписаниеОшибки()); Возврат; КонецПопытки; //Создаем новое письмо (сообщение) Сообщение = Новый ИнтернетПочтовоеСообщение; //Указываем отправителя Сообщение.Отправитель = "user********"; Для Каждого ЗначКому из Кому Цикл Сообщение.Получатели.Добавить(ЗначКому); КонецЦикла; //Заполняем получателя //Сообщение.Получатели.Добавить("dyachok.n@"); //Пишем тему письма Сообщение.Тема = ДанныеПисьма.Тема; //Формируем текст письма,указываем тип письма Сообщение.Тексты.Добавить(ДанныеПисьма.Тело,ТипТекстаПочтовогоСообщения.HTML); //При необходимости делаем вложение с файлом Если ТипЗнч(Вложения)= Тип("Строка") тогда Сообщение.Вложения.Добавить(Вложения); ИначеЕсли ТипЗнч(Вложения) = Тип("Массив") тогда Для Каждого Файл из Вложения Цикл Сообщение.Вложения.Добавить(Файл); КонецЦикла; КонецЕсли; //Непосредственно отправка сообщения Почта.Послать(Сообщение); //После отправки закрываем соединение Почта.Отключиться(); Сообщение = Неопределено; Почта = Неопределено; КонецПроцедуры Процедура УдалитьТемпФайл(ИмяФайла) ФайлНаДиске = Новый Файл(ИмяФайла); Если ФайлНаДиске.Существует() тогда УдалитьФайлы(ИмяФайла); КонецЕсли; КонецПроцедуры &НаСервереБезКонтекста Функция ВернутьГруппы(Знач Ном) //Ном = Справочники.Номенклатура.СоздатьЭлемент(); СтруктураГрупп = Новый Структура("Группа1О,Группа2О,Группа3О,Группа1С,Группа2С,Группа3С"); Поиск = Ном; ТекУровень = Поиск.Уровень(); Пока Истина Цикл Если Поиск.Пустая() тогда прервать; КонецЕсли; Если НЕ Поиск.ЭтоГруппа тогда Поиск = Поиск.Родитель; продолжить; КонецЕсли; ТекУровень = Поиск.Уровень()+1; Если ТекУровень = 1 тогда СтруктураГрупп.Группа1О = Поиск; СтрокаВозврата = ""; Если НЕ Поиск.КодСортировки=0 тогда СтрокаВозврата=СтрокаВозврата+Формат(Поиск.КодСортировки,"ЧЦ=3; ЧДЦ=0; ЧН=0; ЧВН=; ЧГ=0")+". "; КонецЕсли; СтруктураГрупп.Группа1С=СтрокаВозврата+Поиск.Наименование + " ("+Поиск.Код +")"; ИначеЕсли ТекУровень = 2 тогда СтруктураГрупп.Группа2О = Поиск; СтрокаВозврата = ""; Если НЕ Поиск.КодСортировки=0 тогда СтрокаВозврата=СтрокаВозврата+Формат(Поиск.КодСортировки,"ЧЦ=3; ЧДЦ=0; ЧН=0; ЧВН=; ЧГ=0")+". "; КонецЕсли; СтруктураГрупп.Группа2С=СтрокаВозврата+Поиск.Наименование + " ("+Поиск.Код +")"; ИначеЕсли ТекУровень = 3 тогда СтруктураГрупп.Группа3О = Поиск; СтрокаВозврата = ""; Если НЕ Поиск.КодСортировки=0 тогда СтрокаВозврата=СтрокаВозврата+Формат(Поиск.КодСортировки,"ЧЦ=3; ЧДЦ=0; ЧН=0; ЧВН=; ЧГ=0")+". "; КонецЕсли; СтруктураГрупп.Группа3С=СтрокаВозврата+Поиск.Наименование + " ("+Поиск.Код +")"; КонецЕсли; Поиск = Поиск.Родитель; КонецЦикла; Возврат СтруктураГрупп; КонецФункции