Как стать автором
Поиск
Написать публикацию
Обновить

1С. Или первый опыт работы с журналом регистрации

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