Книга знаний

1С:Предприятие / Администрирование

По ночам должны работать роботы…

Автор статьи: Ангел-Хоронитель | Редакторы: Волшебник, Gepard
Последняя редакция №15 от 27.05.06 | История
URL: http://kb.mista.ru/article.php?id=234

По ночам должны работать роботы…



Наверное каждый из вас сталкивался с тем, что нужно что-то сделать в базе в монопольном режиме. И многие сталкивались с тем, что, чтобы сделать это, нужно выгонять всех пользователей, у которых много работы, или сидеть и делать это по ночам.
Восстановление последовательности, удаление помеченных на удаление объектов да и просто какие-то операции, требующие того, чтобы вся работа была закончена.
Фирма 1С не позаботилась о бедных пользователях, так давайте предоставим эту возможность… роботу. Точнее автоматической обработке.

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

Функция восстановления последовательностей.



Итак, последовательность. В 1С последовательность – это цепочка документов проведенных по порядку, в зависимости от даты и времени. Граница последовательности – последний документ, проведенный без нарушения последовательности. Следовательно, для восстановления последовательности мы должны перепровести все документы, входящие в последовательность, по порядку, начиная с последнего в последовательности.
Кстати, в ТиС есть стандартная Функция глВосстановлениеПоследовательности(), можете использовать и ее, но своя рубашка ближе к телу, а доверия фирма 1С давно уже не оправдывает :)
Моя функция приведена ниже с комментариями, я думаю их будет достаточно для понимания.

Функция ВосстановлениеПоследовательностей() Экспорт
    Перем СтараяПозицияТА;                                                
      
    ТекстОшибки = СоздатьОбъект("Текст");
     
    //сохраним позицию ТА
    СтараяПозицияТА = ПолучитьПозициюТА();
    БылиОшибкиПроведения = 0;
    
    Документ=СоздатьОбъект("Документ");
    Объект=СоздатьОбъект("Документ");
    
    //получим наименьшую дату границ последовательностей
    ВыбДата = Последовательность.ПолучитьАтрибут(Метаданные.Последовательность(1)).ПолучитьДату();
    Для nn=1 По Метаданные.Последовательность() Цикл
        Дат = Последовательность.ПолучитьАтрибут(Метаданные.Последовательность(nn)).ПолучитьДату();
        ВыбДата = Мин(Дат,ВыбДата);    
    КонецЦикла;    
    
    //выберем документы
    Документ.ВыбратьДокументы(ВыбДата,);
    
    Пока (Документ.ПолучитьДокумент()>0) и (БылиОшибкиПроведения = 0) Цикл
         
        //пропускаем непроведенные
        Если Документ.Проведен()=0 Тогда
            Продолжить;
        КонецЕсли;
        
        ТекДок = Документ.ТекущийДокумент();
        //проверим на принадлежность последовательностям
        Принадлежит=0;
        Для nn=1 По Метаданные.Последовательность() Цикл          
            //поправка от selenat
            Если ТекДок.ПринадлежитПоследовательности(Метаданные.Последовательность(nn)) = 1 Тогда
                Принадлежит = 1;
                Прервать;
            КонецЕсли;
        КонецЦикла;            
        
        Если МонопольныйРежим()>0 Тогда
            // если оперативный документ находится за ТА, то ТА надо передвинуть в любом случае
            Если (ТекДок.СравнитьТА()>0) или (Принадлежит = 1) Тогда
                БылаПозиция = ПолучитьПозициюТА();
                УстановитьТАНа(ТекДок);
                Если БылаПозиция = ПолучитьПозициюТА() Тогда
                    // не удалось поменять (например, были открытые документы)   
                    ТекстОшибки.ДобавитьСтроку("       Не удалось переместить ТА!");
                    БылиОшибкиПроведения = 1;
                    Продолжить;
                КонецЕсли;
            КонецЕсли;
        КонецЕсли;   
        
        Если Принадлежит=1 Тогда
            Объект.НайтиДокумент(ТекДок);     
            //пытаемся перепровести
            Попытка                           
                Если Объект.Провести() = 0 Тогда   
                    ТекстОшибки.ДобавитьСтроку("       Не удалось провести документ "+Строка(Объект));
                    БылиОшибкиПроведения = 1;
                КонецЕсли;    
            Исключение                                      
                ТекстОшибки.ДобавитьСтроку("       Не удалось провести документ "+Строка(Объект));
                ТекстОшибки.ДобавитьСтроку("       Ошибка: "+ОписаниеОшибки());
                БылиОшибкиПроведения = 1; 
                Прервать;
            КонецПопытки;
        КонецЕсли;       
        
        //сохраним последний проведенный документ, для позиционирования на нем последовательностей
        ПослДок = Объект.ТекущийДокумент();
        
    КонецЦикла;    
     
    //позиционируем последовательности на последнем проведенном документе
    Для nn=1 По Метаданные.Последовательность() Цикл
        Последовательность.ПолучитьАтрибут(Метаданные.Последовательность(nn)).Установить(ПослДок);
    КонецЦикла;    
     
    //возвращаем старую ТА
    Если (МонопольныйРежим()>0) и (СтараяПозицияТА <> ПолучитьПозициюТА()) Тогда
        УстановитьТАПо(СтараяПозицияТА);
    КонецЕсли;
    
    Возврат ?(БылиОшибкиПроведения = 0,1,ТекстОшибки);
    
КонецФункции    // ВосстановлениеПоследовательностей()


За некоторые замечания по оптимизации большое спасибо selenat.


Функция удаления помеченных элементов справочников и документов.



Далее на повестке дня у нас – удаление помеченных элементов. Есть такие, кто не будет читать эту статью, а просто переберет элементы и напишет Элемент.Удалить(1). Но наверное есть и те, кто так уже сделал и кому интересно, а как же все сделать правильно и избежать тех проблем, которые у них возникли :)
А правильный способ – это удалять только те элементы, на которые после удаления не останется ссылок в базе. То есть если ссылок совсем нет, или ссылающиеся элементы будут также удалены.

Функция ИнфаОбЭлементе(Эл)
    Стр = "";       
    Если ТипЗначенияСтр(Эл) = "Справочник" Тогда
        Стр = "Справочник." + Эл.Вид() + " " + Эл.Код + " " + Эл.Наименование;  
    ИначеЕсли ТипЗначенияСтр(Эл) = "Документ" Тогда
        //вместо глНазваниеДокументаВжурнале(Эл) можно просто написать Эл
        Стр = "Документ Номер: " + Эл.НомерДок + " " + глНазваниеДокументаВжурнале(Эл); 
    КонецЕсли;    
    Возврат(Стр);
КонецФункции //ИнфаОбЭлементе()

//*******************************************
Функция УдалениеПомеченных()             
    
    Спис = СоздатьОбъект("СписокЗначений"); 
    ТабСсыл = СоздатьОбъект("ТаблицаЗначений"); 
    ОтчТекст = СоздатьОбъект("Текст");
    
    //составляем список помеченных на удаление
    НайтиПомеченныеНаУдаление(Спис);
     
    
    Если Спис.РазмерСписка() > 0 Тогда       
        //если есть помеченные - удаляем
        УдалитьОбъекты(Спис,1,ТабСсыл);      
               
        //если остались неудаленные
        Если ТабСсыл.КоличествоСтрок() > 0 Тогда  
            //сообщаем только об удаленных
            Для nn = 1 По Спис.РазмерСписка() Цикл
                Элем = Спис.ПолучитьЗначение(nn);
                Если ТабСсыл.НайтиЗначение(Элем,,"Объект") = 0 Тогда
                          ОтчТекст.ДобавитьСтроку("Удалили "+ИнфаОбЭлементе(Элем));
                КонецЕсли;
            КонецЦикла;
                                    
            //сообщаем только о неудаленных
             ТабСсыл.ВыбратьСтроки(); 
             Элем = "";
            Пока ТабСсыл.ПолучитьСтроку() = 1 Цикл     
                Если Элем <> ТабСсыл.Объект Тогда
                          Элем = ТабСсыл.Объект; 
                    ОтчТекст.ДобавитьСтроку("Не удалось удалить: " + ИнфаОбЭлементе(ТабСсыл.Объект));
                    ОтчТекст.ДобавитьСтроку("  Ссылки и комментарии:");
                КонецЕсли;
                    ОтчТекст.ДобавитьСтроку("                 " + ТабСсыл.Описание);
            КонецЦикла;     
        Иначе                                                   
            //если удалились все, то выведем их список
             Для nn = 1 По Спис.РазмерСписка() Цикл
                          ОтчТекст.ДобавитьСтроку("Удалили "+ИнфаОбЭлементе(Спис.ПолучитьЗначение(nn)));
            КонецЦикла;
        КонецЕсли;     
        
    КонецЕсли;         
    
    Возврат(ОтчТекст);
    
КонецФункции //УдалениеПомеченных() 


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


Организация автоматического запуска нашей обработки.


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

    1.    Завел нового пользователя Service. Имя лучше на латинице задавать, ниже опишу почему. Пароль лучше не самый простой, любопытных пользователей много и им будет очень интересно, зачем это тут.
    2.    В глобальном модуле в процедуре ПриНачалеРаботыСистемы открытие нового периода сделал с условием «Если ИмяПользователя() <> "Service" Тогда», ибо решил доверить его нашему боту.
    3.    В конце процедуры ПриНачалеРаботыСистемы прописал:

    Если ИмяПользователя() = "Service" Тогда 
        Если Константа. АвтоматическиеРаботы = 1 Тогда
            ОткрытьФорму("Отчет",,""+КаталогИБ()+"Автомат.ert");
        КонецЕсли;
        ЗавершитьРаботуСистемы(0);
    КонецЕсли;

    4.    Добавил константу АвтоматическиеРаботы со значением 1 или 0, и дал права на ее редактирование нужным людям (себе и еще раз себе :] )
    5.    С установленной в 0 константой зашел в базу под новой учеткой и позакрывал всякую ерунду (Советы дня и пр.), а также проверил, чтобы не выскакивала какая-нибудь незапланированная лабуда.
    6.    Также в каталог базы кинул bat файл, с таким текстом:

        del *.cdx
        "C:\Program Files\1Cv77\BIN\1CV7s.exe" ENTERPRISE /M /DD:\1C\DB /NService /P159

Замечу, сначала удаляются все файлы cdx, чтобы при монопольном запуске не выдавалось противное окошко с вопросом о переиндексации (если отсутствуют индексные файлы, то переиндексация пройдет принудительно, без лишних вопросов), затем запускается 1С в нужной базе с нужным юзером (если бы имя юзера было на кириллице, вас бы поджидал большой облом :-} ) .
    7.    Проверил работоспособность вручную, затем создал новое задание в планировщике, поставил на 1 ночи, ибо работают у нас и до полуночи некоторые.

Текст обработки Автомат.ert (соответственно к нему еще надо приписать приведенные выше функции)




//*******************************************
Функция ТекВремя(Сп=0) Экспорт  
    Часов = 0; Минут = 0; Секунд = 0;
    ТекущееВремя(Часов,Минут,Секунд);
    Возврат(?(Сп=0,"","" + ТекущаяДата() + " ") + Формат(Часов,"Ч(0)2") + ":"
        + Формат(Минут,"Ч(0)2") + ":" + Формат(Секунд,"Ч(0)2"));
КонецФункции    

//*******************************************
Процедура ПриОткрытии()         
    
    Если Константа.АвтоматическиеРаботы = 1 Тогда
        
        Текст = СоздатьОбъект("Текст");   
        path = ""+КаталогИБ()+"avtomat.txt";
        Если ФС.СуществуетФайл(path) = 1 Тогда
            Текст.Открыть(path);
        КонецЕсли;     
        Текст.ДобавитьСтроку("");  
        Текст.ДобавитьСтроку("");  
        Текст.ДобавитьСтроку("- - -- - - - - - - - - - - - - - - - - - - - - - ");  
        Текст.ДобавитьСтроку("Начало - "+ТекВремя(1)); 
        Текст.Записать(path);
        
        Текст.ДобавитьСтроку("");  
        Если МонопольныйРежим()=0 Тогда
            Текст.ДобавитьСтроку("Был немонопольный режим - ТА не перенесли, последовательности не востановили!"); 
        Иначе                             

            Текст.ДобавитьСтроку("Начинаем переносить ТА  "+ТекВремя());
            Текст.Записать(path);
            //переносим ТА
            Если РабочаяДата() > ПолучитьДатуТА() Тогда    
                УстановитьТАНа(РабочаяДата());
                Текст.ДобавитьСтроку("Перенесли ТА "+ТекВремя());
            Иначе
                       Текст.ДобавитьСтроку("Переносить ТА не потребовалось "+ТекВремя());
            КонецЕсли;    
                                        
            //восстанавливаем последовательности
            Текст.ДобавитьСтроку("");
            Текст.ДобавитьСтроку("Начали восстановление последовательностей  "+ТекВремя());  
            Текст.Записать(path);  
            Рез = ВосстановлениеПоследовательностей(); 
            Если Рез = 1 Тогда
                Текст.ДобавитьСтроку("Закончили успешно  "+глТекВремя());
            Иначе
                Текст.ДобавитьСтроку(глТекВремя() + "Произошла слудующая ошибка при
                          восстановлении:"); 
                Для nn = 1 По Рез.КоличествоСтрок() Цикл
                         Текст.ДобавитьСтроку(Рез.ПолучитьСтроку(nn));
                КонецЦикла;
            КонецЕсли;
            Текст.Записать(path);  
                                           
            //удаляем помеченные
            ВремТекст = УдалениеПомеченных();
            Если ВремТекст.КоличествоСтрок() > 0 Тогда    
            Текст.ДобавитьСтроку("");
            Текст.ДобавитьСтроку("Провели удаление помеченных элементов  "+ТекВремя());  
                Для nn = 1 По ВремТекст.КоличествоСтрок() Цикл
                    Текст.ДобавитьСтроку(ВремТекст.ПолучитьСтроку(nn));       
                КонецЦикла;       
            КонецЕсли;            
            
        КонецЕсли;                                     
        
        Текст.Записать(path);

    КонецЕсли;    
    
    //при установленной программе TheBat можно отправить письмо с текстом отчета
    ЗапуститьПриложение("C:\TheBat\TheBat.exe /NOLOGO /MAILU=Мой ящик;TO=admin@company.com;"
        + "S=Проверка;TEXT=" + path + " /EXIT");

    СтатусВозврата(0);    
    Возврат;
    
КонецПроцедуры 

Описание | Рубрикатор | Поиск | ТелепатБот | Захваченные статьи | Установки | Форум
© Станислав Митичкин (Волшебник), 2005-2025 | Mista.ru

Яндекс.Метрика