Pull to refresh

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()
из моего родного С++.
Спасибо за внимание уважаемые Хабратья
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.