Доброй ночи дорогие соратники!
Пишу свой первый пост, кому-то он покажется малоинтересным, кому-то не столь профессиональным, однако я решил поделиться своим опытом работы с журналом регистрации в программном продукте 1С.
Предисловие
Буквально на днях, по системе опыта, выпустившись из ВУЗа и защитив свой многострадальный диплом, внезапно перешедший от C# к 1С, я устроился программистом в X компанию. Прошло почти 6 месяцев, было проделано много работы, был буквально 'до дыр' использован всемогущий Google и вот я подошел к довольно интересной теме: использование журнала регистрации программным путем.
Добро пожаловать тем, кто заинтересован.
Примерное описание задачи
Необходимо выявить документы, использовав журнал регистрации, которые изменялись в период с A до B, но при этом, были созданы в любой промежуток времени до точки A.
Решение
Изначально, вполне логично, было решено использовать стандартный журнал(читай дальше: Журнал Регистрации), который позволяет зафиксировать в любом удобно-пищеваримом виде изменения по неким документам(C++ = Класс) по фильтрам. После некоего совещания, было решено, что стандартный журнал регистрации, точнее его формирование, занимает слишком много времени, соответственно, при вычислении любых изменений по документу в Период = 1 день, формирование занимает в районе ~30 минут. Слишком долго. «Соль» в том, что стандартный журнал использует динамическое обновление формы, которое в условиях движка 1С прописано настолько криво, что волосы дыбом встают. Руководителем проекта было решено использовать программный метод выявления изменений. Что из этого получилось:
-Небольшой код дает преимущество во времени выполнения ( к примеру, формирование журнала по 6-и видам документов «первички» по фильтрам всех пользователей занимает примерно минуту)
-Выгрузка данных в формат XML занимает в пределах минуты(+- 20 секунд на каждую неделю)
-Чтение формата XML занимает примерно 7 минут(общий 'вес' XML ~20 МБ)
-Расшифровка(чтение XML по тегам, внесение в ТЗ и выделение подстрок) занимает ~20 секунд
Итого: ~8 минут рабочего времени. И, как видим, слишком не хватает
Спасибо за внимание уважаемыеХабратья
Пишу свой первый пост, кому-то он покажется малоинтересным, кому-то не столь профессиональным, однако я решил поделиться своим опытом работы с журналом регистрации в программном продукте 1С.
Предисловие
Буквально на днях, по системе опыта, выпустившись из ВУЗа и защитив свой многострадальный диплом, внезапно перешедший от C# к 1С, я устроился программистом в X компанию. Прошло почти 6 месяцев, было проделано много работы, был буквально 'до дыр' использован всемогущий Google и вот я подошел к довольно интересной теме: использование журнала регистрации программным путем.
Добро пожаловать тем, кто заинтересован.
Примерное описание задачи
Необходимо выявить документы, использовав журнал регистрации, которые изменялись в период с A до B, но при этом, были созданы в любой промежуток времени до точки A.
Решение
Изначально, вполне логично, было решено использовать стандартный журнал(читай дальше: Журнал Регистрации), который позволяет зафиксировать в любом удобно-пищеваримом виде изменения по неким документам(C++ = Класс) по фильтрам. После некоего совещания, было решено, что стандартный журнал регистрации, точнее его формирование, занимает слишком много времени, соответственно, при вычислении любых изменений по документу в Период = 1 день, формирование занимает в районе ~30 минут. Слишком долго. «Соль» в том, что стандартный журнал использует динамическое обновление формы, которое в условиях движка 1С прописано настолько криво, что волосы дыбом встают. Руководителем проекта было решено использовать программный метод выявления изменений. Что из этого получилось:
-Небольшой код дает преимущество во времени выполнения ( к примеру, формирование журнала по 6-и видам документов «первички» по фильтрам всех пользователей занимает примерно минуту)
-Выгрузка данных в формат XML занимает в пределах минуты(+- 20 секунд на каждую неделю)
ФайлПуть = "C:\transfer\1C_EventLog1.xml";
Сообщить("[" + ТекущаяДата() + "]: Выгрузка журнала начата за период с [" + ДатаНачала + "] по [" + ДатаОкончания + "]...", СтатусСообщения.Информация);
// Генерируем массив изменений по документам: Изменение, Удаление, Изменение периода в регистрах, Проведение, Отмена проведения
МассивСобытий = Новый Массив;
МассивСобытий.Добавить("_$Data$_.Update");
МассивСобытий.Добавить("_$Data$_.Delete");
МассивСобытий.Добавить("_$Data$_.Post");
МассивСобытий.Добавить("_$Data$_.Unpost");
// Массив пользователей, по которым строится фильтр
МассивЮзеров = Новый Массив;
МассивЮзеров.Добавить("Урывская К. К");
МассивЮзеров.Добавить("Гарифулина А. Ф.");
МассивЮзеров.Добавить("Конкина Е.Г.");
МассивЮзеров.Добавить("Щеголева Т.И.");
МассивЮзеров.Добавить("Павлюк А. В.");
МассивЮзеров.Добавить("Левченкова Н.А.");
МассивЮзеров.Добавить("Иванчёва Т.Ю.");
МассивЮзеров.Добавить("Фурсова Н. В.");
МассивЮзеров.Добавить("Батусова Е.С.");
МассивЮзеров.Добавить("Глебов И.А.");
МассивЮзеров.Добавить("Рунов И. А.");
МассивЮзеров.Добавить("Ланцов Д.А.");
МассивЮзеров.Добавить("Пыцкий А. Н.");
МассивЮзеров.Добавить("Жукова Е.С.");
МассивЮзеров.Добавить("Гловацкая Ю.А.");
МассивЮзеров.Добавить("Жукова А. К.");
МассивЮзеров.Добавить("Капирова О.В.");
МассивЮзеров.Добавить("Мандрыкина Т.А.");
МассивЮзеров.Добавить("Варганова О. В.");
МассивЮзеров.Добавить("Смирнова Е.Б.");
МассивЮзеров.Добавить("Поплаухина В. В.");
МассивЮзеров.Добавить("Шихова М.В.");
// Определяем массив данных по которым нужны изменения
МассивМетаданных = Новый Массив;
МассивМетаданных.Добавить(Метаданные.Документы.РеализацияТоваровУслуг);
МассивМетаданных.Добавить(Метаданные.Документы.ПоступлениеТоваровУслуг);
МассивМетаданных.Добавить(Метаданные.Документы.ВозвратТоваровОтПокупателя);
МассивМетаданных.Добавить(Метаданные.Документы.ВозвратТоваровПоставщику);
МассивМетаданных.Добавить(Метаданные.Документы.СписаниеТоваров);
МассивМетаданных.Добавить(Метаданные.Документы.ОприходованиеТоваров);
МассивМетаданных.Добавить(Метаданные.Документы.ПеремещениеТоваров);
//Создаем структуру "Фильтр", к которой применим ранее заданные переменные для условий выборки из лога:
Фильтр = Новый Структура("ДатаНачала, ДатаОкончания, Пользователь, Событие, Метаданные");
Фильтр.ДатаНачала = ДатаНачала;
Фильтр.ДатаОкончания = ДатаОкончания;
Фильтр.Метаданные = МассивМетаданных;
Фильтр.Событие = МассивСобытий;
Фильтр.Пользователь = МассивЮзеров;
// Выгружаем журнал, берем только колонки, перечисленные в третьем параметре:
ВыгрузитьЖурналРегистрации(ФайлПуть, Фильтр, "Дата, ИмяПользователя, Событие, Метаданные, Данные, ПредставлениеДанных");
Сообщить("[" + ТекущаяДата() + "]: Выгрузка журнала завершена в " + ФайлПуть,СтатусСообщения.Информация);
-Чтение формата XML занимает примерно 7 минут(общий 'вес' XML ~20 МБ)
ТаблицаДанных = Новый ТаблицаЗначений;
ТаблицаДанных.Колонки.Добавить("Номер");
ТаблицаДанных.Колонки.Добавить("Дата");
ТаблицаДанных.Колонки.Добавить("Тип");
ТаблицаДанных.Колонки.Добавить("Пользователь");
ТекстовыйДокумент = Новый ТекстовыйДокумент;
//Читаем XML файл по тегу описания документа и записываем в ТЗ
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл("C:\transfer\1C_EventLog1.xml");
ПостроительDOM = Новый ПостроительDOM;
ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);
Event = ДокументDOM.ПолучитьЭлементыПоИмени("v8e:Event");
Для Позиция = 0 По Event.Количество()-1 Цикл
ДочерниеУзлы = Event[Позиция].ДочерниеУзлы;
Для Каждого Узел Из ДочерниеУзлы Цикл
Если Узел.ИмяУзла = "v8e:DataPresentation" Тогда
НоваяСтрокаТаблицы = ТаблицаДанных.Добавить();
СтруктураРасшифрованныхДанныхXML = РасшифроватьЗаписьXML(Узел.ТекстовоеСодержимое);
Если СтруктураРасшифрованныхДанныхXML <> Неопределено Тогда
НоваяСтрокаТаблицы.Номер = СтруктураРасшифрованныхДанныхXML.Номер;
НоваяСтрокаТаблицы.Дата = СтруктураРасшифрованныхДанныхXML.Дата;
НоваяСтрокаТаблицы.Тип = СтруктураРасшифрованныхДанныхXML.Тип;
Иначе
Прервать;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЦикла;
ЧтениеXML.Закрыть();
ТаблицаДанных.Свернуть("Номер, Тип, Дата");
Для Каждого Строка Из ТаблицаДанных Цикл
ТекстовыйДокумент.ДобавитьСтроку("Тип: " + Строка.Тип + ", номер: " + Строка.Номер + " ; дата: " + Строка.Дата + ";!");
КонецЦикла;
//ТаблицаДанных.Сортировать("Дата Возр");
Сообщить("ИТОГО по итогу за период обнаружено " + ТаблицаДанных.Количество() + " документов!");
ТекстовыйДокумент.Записать("C:\transfer\fail.txt");
-Расшифровка(чтение XML по тегам, внесение в ТЗ и выделение подстрок) занимает ~20 секунд
Функция РасшифроватьЗаписьXML(ТекстовоеСодержимоеУзла)
СтруктураДанных = Новый Структура;
Если Лев(ТекстовоеСодержимоеУзла, 10) = "Реализация" Тогда
ТипДокумента = Лев(ТекстовоеСодержимоеУзла, 27);
//ПодстрокаНомераДокумента = СокрЛП(Сред(ТекстовоеСодержимоеУзла, 28, 11));
ПодстрокаНомераДокумента = СокрЛП(Лев(СтрЗаменить(ТекстовоеСодержимоеУзла, ТипДокумента, ""), 12));
// Парсим дату документа, алгоритм подходит для всех типов документов
СтрокаДатаИВремяДокумента = Прав(ТекстовоеСодержимоеУзла,19);
СтрокаДатаДокумента = СокрЛП(СтрЗаменить(Лев(СтрокаДатаИВремяДокумента,10), ".", ""));
ДатаСтрокой = Прав(СтрокаДатаДокумента, 4) + Сред(СтрокаДатаДокумента, 3, 2) + Лев(СтрокаДатаДокумента, 2);
КонечнаяДатаПоДокументуИзXML = Дата(ДатаСтрокой);
Если КонечнаяДатаПоДокументуИзXML >= ДатаНачала Тогда
Сообщить("Документ реализации номер: " + ПодстрокаНомераДокумента + " был создан позже.");
Иначе
СтруктураДанных.Вставить("Номер", ПодстрокаНомераДокумента);
СтруктураДанных.Вставить("Дата", КонечнаяДатаПоДокументуИзXML);
СтруктураДанных.Вставить("Тип", ТипДокумента);
Сообщить("Документ реализации номер: " + ПодстрокаНомераДокумента + " подходит.");
Возврат СтруктураДанных;
КонецЕсли;
ИначеЕсли Лев(ТекстовоеСодержимоеУзла, 11) = "Поступление" Тогда
ТипДокумента = Лев(ТекстовоеСодержимоеУзла, 27);
ПодстрокаНомераДокумента = СокрЛП(Лев(СтрЗаменить(ТекстовоеСодержимоеУзла, ТипДокумента, ""), 12));
Если Найти(ПодстрокаНомераДокумента, "от") > 0 Тогда
ПодстрокаНомераДокумента = СокрЛП(Лев(ПодстрокаНомераДокумента, 7));
КонецЕсли;
СтрокаДатаИВремяДокумента = Прав(ТекстовоеСодержимоеУзла,19);
СтрокаДатаДокумента = СокрЛП(СтрЗаменить(Лев(СтрокаДатаИВремяДокумента,11), ".", ""));
ДатаСтрокой = Прав(СтрокаДатаДокумента, 4) + Сред(СтрокаДатаДокумента, 3, 2) + Лев(СтрокаДатаДокумента, 2);
КонечнаяДатаПоДокументуИзXML = Дата(ДатаСтрокой);
Если КонечнаяДатаПоДокументуИзXML >= ДатаНачала Тогда
Сообщить("Документ поступления номер: " + ПодстрокаНомераДокумента + " был создан позже.");
Иначе
СтруктураДанных.Вставить("Номер", ПодстрокаНомераДокумента);
СтруктураДанных.Вставить("Дата", КонечнаяДатаПоДокументуИзXML);
СтруктураДанных.Вставить("Тип", ТипДокумента);
Сообщить("Документ поступления номер: " + ПодстрокаНомераДокумента + " подходит.");
Возврат СтруктураДанных;
КонецЕсли;
ИначеЕсли Сред(ТекстовоеСодержимоеУзла,19, 10) = "покупателя" Тогда
ТипДокумента = Лев(ТекстовоеСодержимоеУзла, 30);
ПодстрокаНомераДокумента = СокрЛП(Лев(СтрЗаменить(ТекстовоеСодержимоеУзла, ТипДокумента, ""), 12));
СтрокаДатаИВремяДокумента = Прав(ТекстовоеСодержимоеУзла,19);
СтрокаДатаДокумента = СокрЛП(СтрЗаменить(Лев(СтрокаДатаИВремяДокумента,10), ".", ""));
ДатаСтрокой = Прав(СтрокаДатаДокумента, 4) + Сред(СтрокаДатаДокумента, 3, 2) + Лев(СтрокаДатаДокумента, 2);
КонечнаяДатаПоДокументуИзXML = Дата(ДатаСтрокой);
Если КонечнаяДатаПоДокументуИзXML >= ДатаНачала Тогда
Сообщить("Документ реализации номер: " + ПодстрокаНомераДокумента + " был создан позже.");
Иначе
СтруктураДанных.Вставить("Номер", ПодстрокаНомераДокумента);
СтруктураДанных.Вставить("Дата", КонечнаяДатаПоДокументуИзXML);
СтруктураДанных.Вставить("Тип", ТипДокумента);
Сообщить("Документ возврат товаров от покупателя номер: " + ПодстрокаНомераДокумента + " подходит.");
Возврат СтруктураДанных;
КонецЕсли;
ИначеЕсли Сред(ТекстовоеСодержимоеУзла,16, 10) = "поставщику" Тогда
ТипДокумента = Лев(ТекстовоеСодержимоеУзла, 27);
ПодстрокаНомераДокумента = СокрЛП(Лев(СтрЗаменить(ТекстовоеСодержимоеУзла, ТипДокумента, ""), 12));
//Выбираем дату документа из строки и преобразовываем в формат даты
СтрокаДатаИВремяДокумента = Прав(ТекстовоеСодержимоеУзла,19);
СтрокаДатаДокумента = СокрЛП(СтрЗаменить(Лев(СтрокаДатаИВремяДокумента,10), ".", ""));
ДатаСтрокой = Прав(СтрокаДатаДокумента, 4) + Сред(СтрокаДатаДокумента, 3, 2) + Лев(СтрокаДатаДокумента, 2);
КонечнаяДатаПоДокументуИзXML = Дата(ДатаСтрокой);
Если КонечнаяДатаПоДокументуИзXML >= ДатаНачала Тогда
Сообщить("Документ реализации номер: " + ПодстрокаНомераДокумента + " был создан позже.");
Иначе
СтруктураДанных.Вставить("Номер", ПодстрокаНомераДокумента);
СтруктураДанных.Вставить("Дата", КонечнаяДатаПоДокументуИзXML);
СтруктураДанных.Вставить("Тип", ТипДокумента);
Сообщить("Документ возврат товаров поставщику номер: " + ПодстрокаНомераДокумента + " подходит.");
Возврат СтруктураДанных;
КонецЕсли;
ИначеЕсли Лев(ТекстовоеСодержимоеУзла, 8) = "Списание" Тогда
ТипДокумента = Лев(ТекстовоеСодержимоеУзла, 17);
ПодстрокаНомераДокумента = СокрЛП(Лев(СтрЗаменить(ТекстовоеСодержимоеУзла, ТипДокумента, ""), 12));
Если Найти(ПодстрокаНомераДокумента, "от") > 0 Тогда
ПодстрокаНомераДокумента = СокрЛП(Лев(ПодстрокаНомераДокумента, 8));
КонецЕсли;
СтрокаДатаИВремяДокумента = Прав(ТекстовоеСодержимоеУзла,19);
СтрокаДатаДокумента = СокрЛП(СтрЗаменить(Лев(СтрокаДатаИВремяДокумента,10), ".", ""));
ДатаСтрокой = Прав(СтрокаДатаДокумента, 4) + Сред(СтрокаДатаДокумента, 3, 2) + Лев(СтрокаДатаДокумента, 2);
КонечнаяДатаПоДокументуИзXML = Дата(ДатаСтрокой);
Если КонечнаяДатаПоДокументуИзXML >= ДатаНачала Тогда
Сообщить("Документ реализации номер: " + ПодстрокаНомераДокумента + " был создан позже.");
Иначе
СтруктураДанных.Вставить("Номер", ПодстрокаНомераДокумента);
СтруктураДанных.Вставить("Дата", КонечнаяДатаПоДокументуИзXML);
СтруктураДанных.Вставить("Тип", ТипДокумента);
Сообщить("Документ списания номер: " + ПодстрокаНомераДокумента + " подходит.");
Возврат СтруктураДанных;
КонецЕсли;
ИначеЕсли Лев(ТекстовоеСодержимоеУзла, 13) = "Оприходование" Тогда
ТипДокумента = Лев(ТекстовоеСодержимоеУзла, 22);
ПодстрокаНомераДокумента = СокрЛП(Лев(СтрЗаменить(ТекстовоеСодержимоеУзла, ТипДокумента, ""), 12));
СтрокаДатаИВремяДокумента = Прав(ТекстовоеСодержимоеУзла,19);
СтрокаДатаДокумента = СокрЛП(СтрЗаменить(Лев(СтрокаДатаИВремяДокумента,10), ".", ""));
ДатаСтрокой = Прав(СтрокаДатаДокумента, 4) + Сред(СтрокаДатаДокумента, 3, 2) + Лев(СтрокаДатаДокумента, 2);
КонечнаяДатаПоДокументуИзXML = Дата(ДатаСтрокой);
Если КонечнаяДатаПоДокументуИзXML >= ДатаНачала Тогда
Сообщить("Документ реализации номер: " + ПодстрокаНомераДокумента + " был создан позже.");
Иначе
СтруктураДанных.Вставить("Номер", ПодстрокаНомераДокумента);
СтруктураДанных.Вставить("Дата", КонечнаяДатаПоДокументуИзXML);
СтруктураДанных.Вставить("Тип", ТипДокумента);
Сообщить("Документ оприходования номер: " + ПодстрокаНомераДокумента + " подходит.");
Возврат СтруктураДанных;
КонецЕсли;
ИначеЕсли Лев(ТекстовоеСодержимоеУзла, 11) = "Перемещение" Тогда
ТипДокумента = Лев(ТекстовоеСодержимоеУзла, 20);
ПодстрокаНомераДокумента = СокрЛП(Лев(СтрЗаменить(ТекстовоеСодержимоеУзла, ТипДокумента, ""), 12));
//Выбираем дату документа из строки и преобразовываем в формат даты
СтрокаДатаИВремяДокумента = Прав(ТекстовоеСодержимоеУзла,19);
СтрокаДатаДокумента = СокрЛП(СтрЗаменить(Лев(СтрокаДатаИВремяДокумента,10), ".", ""));
ДатаСтрокой = Прав(СтрокаДатаДокумента, 4) + Сред(СтрокаДатаДокумента, 3, 2) + Лев(СтрокаДатаДокумента, 2);
КонечнаяДатаПоДокументуИзXML = Дата(ДатаСтрокой);
Если КонечнаяДатаПоДокументуИзXML >= ДатаНачала Тогда
Сообщить("Документ реализации номер: " + ПодстрокаНомераДокумента + " был создан позже.");
Иначе
СтруктураДанных.Вставить("Номер", ПодстрокаНомераДокумента);
СтруктураДанных.Вставить("Дата", КонечнаяДатаПоДокументуИзXML);
СтруктураДанных.Вставить("Тип", ТипДокумента);
Сообщить("Документ перемещения номер: " + ПодстрокаНомераДокумента + " подходит.");
Возврат СтруктураДанных;
КонецЕсли;
КонецЕсли;
КонецФункции
Итого: ~8 минут рабочего времени. И, как видим, слишком не хватает
switch()
из моего родного С++. Спасибо за внимание уважаемые