Моменты времени сразу не заработали

В расширениях нельзя использовать границу последовательности.

Поэтому решил написать ее на регистре сведений.

Граница простая, только по организации, примерный код был такой:

Функция ВосстановитьГраницу(Организация, ДП = Неопределено) Экспорт
	ОрганизацияСебестоимости = кпу_Кэш.ОрганизацияСебестоимости(Организация);
	//СтруктураГраницы = ПолучитьГраницу(ОрганизацияСебестоимости);                                                    
	
	СообщитьЖР("КлассическийПартионныйУчет.НачалоВосстановленияГраницы", "Начало восстановления границы: " + ТекущаяДата());
	ПредДата = Неопределено;
	ПредТочнаяДата = Неопределено;
	
	ПредСтруктураГраницы = ПолучитьГраницу(ОрганизацияСебестоимости);
	
	Пока Истина Цикл
		
		СтруктураГраницы = ПолучитьГраницу(ОрганизацияСебестоимости);                                                    
		СтруктураГраницыСледующий = ПолучитьСоседнийДокументГраницы(+1, ОрганизацияСебестоимости, СтруктураГраницы.Документ, СтруктураГраницы.Дата);
		
		Если СтруктураГраницыСледующий.Документ = Неопределено Тогда
			СообщитьЖР("КлассическийПартионныйУчет.КонецВосстановленияГраницы", "Конец восстановления границы: " + ТекущаяДата());
			Возврат истина;
		КонецЕсли;            
		
		Если СтруктураГраницыСледующий.Документ = ПредСтруктураГраницы.Документ Тогда
			СообщитьЖР("КлассическийПартионныйУчет.ЗацикливаниеВосстановленияГраницы", "Зацикливание границы на документе: " + СтруктураГраницы.Документ);
			Возврат ложь;
		КонецЕсли;


		НачалоДня = НачалоДня(СтруктураГраницыСледующий.Дата);
		Если ПредСтруктураГраницы.Дата < СтруктураГраницыСледующий.Дата И ПредСтруктураГраницы.Дата <> '00010101' Тогда
			СообщитьЖР("КлассическийПартионныйУчет.СбойВосстановленияГраницы", "Сбой восстановления границы, границас сместилась с: " + ПредСтруктураГраницы.Дата + " на: " + СтруктураГраницы.Дата);
			Возврат ложь;
		Конецесли;             
		
		ПредСтруктураГраницы = СтруктураГраницыСледующий;
	
		Если ПредДата <> НачалоДня Тогда
			Если кпу_КС.СвойствоСтруктуры(ДП, "ВыводитьСообщенияОДатах", ложь) Тогда
				СообщитьЖР("КлассическийПартионныйУчет.ДатаВосстановленияГраницы", "Начата обработка даты при восстановлении границы:" + Формат(НачалоДня, "ДФ=dd.MM.yyyy"));
			КонецЕсли;                                                                  
			ПредДата = НачалоДня;
		КонецЕсли;  
		
		Ссылка = СтруктураГраницыСледующий.Документ;
		Попытка
			РасчитатьСебестоимостьПоДокументу(Ссылка, ДП); 
		Исключение
			ОписаниеОшибки = ОписаниеОшибки();
			СообщитьЖР("КлассическийПартионныйУчет.Ошибка", "При расчете с-сти по документу: " + Ссылка + " ошибка: " + ОписаниеОшибки);
			СообщитьЖР("КлассическийПартионныйУчет.Прерывание", "Расчет прерван: " + ТекущаяДата());
			Возврат ложь;
		КонецПопытки;

		
	КонецЦикла;   
	
	
КонецФункции

Функция получения границы простая:

Функция ПолучитьГраницу(Организация) Экспорт
	Р = Новый Структура("Документ, Дата", Неопределено, '00010101');
	З = Новый Запрос(
	"ВЫБРАТЬ
	|	Т.Организация КАК Организация,
	|	Т.Дата КАК Дата,
	|	Т.Документ КАК Документ
	|ИЗ
	|	РегистрСведений.кпу_ГраницаПоследовательности КАК Т
	|ГДЕ
	|	Т.Организация = &Организация");
	З.УстановитьПараметр("Организация", Организация);
	Выборка = З.Выполнить().Выбрать();
	Если Выборка.Следующий() Тогда
		Р.Дата = Выборка.Дата;
		Р.Документ = Выборка.Документ;
	КонецЕсли;
	Возврат Р;
КонецФункции  

А вот с моментами я что-то затупил… Не нашел как сравнивать их в запросе, поэтому сравнивал их уже в результате запроса и не заработало — вылетало по зацикливанию, где-то неправильно я считал моменты:

Функция ПолучитьСоседнийДокументГраницы(Направление, Организация, ОпорныйДокумент, Дата) Экспорт
	Р = Новый Структура("Документ, Дата", Неопределено, '00010101');
	//Направление = +1 Следующий, -1 предыдущий
	
	З = Новый Запрос(
	"ВЫБРАТЬ РАЗЛИЧНЫЕ
	|	Т.Регистратор КАК Документ,
	|	Т.Период КАК Дата
	|ИЗ
	|	РегистрНакопления.Запасы КАК Т
	|ГДЕ
	|	Т.Период В
	|			(ВЫБРАТЬ ПЕРВЫЕ 1
	|				Т.Период КАК Дата
	|			ИЗ
	|				РегистрНакопления.Запасы КАК Т
	|			ГДЕ
	|				Т.Организация = &Организация 
	|				И &Условие
	|				И Т.Регистратор <> &ОпорныйДокумент
	|			УПОРЯДОЧИТЬ ПО
	|				Дата УБЫВ)" ); 
	
	Если Направление = 1 Тогда
		Условие = "Т.Период >= &Дата";
		Добавка = "Возр";
	Иначе
		Условие = "Т.Период <= &Дата";
		Добавка = "Убыв";              
	КонецЕсли;
	
	З.Текст = СтрЗаменить(З.Текст, "&Условие", Условие);
	З.Текст = СтрЗаменить(З.Текст, "УБЫВ", Добавка);
	
	З.УстановитьПараметр("Организация", Организация);
	З.УстановитьПараметр("Дата", Дата);
	З.УстановитьПараметр("ОпорныйДокумент", ОпорныйДокумент);
	
	//ДОкументы с одной датой сравниваем по моменту
	ТЗ = З.Выполнить().Выгрузить();
	МассивДокументов = ТЗ.ВыгрузитьКолонку("Документ");
	ОпорныйДокументДляПроверки = Неопределено;                                                      
	Если ТЗ.Количество() > 0 И ТЗ[0].Дата = Дата Тогда                                   
		ОпорныйДокументДляПроверки = ОпорныйДокумент;
	Конецесли;                                               
	
	//Ищем ближайший к опорному документ
	Если Направление = +1 Тогда              
		//Максимальный после опорного и затем минимальный из них
		ФильтрМассивДокументов = ОтобратьДокументыПоМоментамВремени(+1, МассивДокументов, ОпорныйДокументДляПроверки);
		ИскДокумент = КрайнийИзМоментовВремени(ФильтрМассивДокументов, -1);
	Иначе
		//Минимальный перед опорным и затем максимальный из них
		ФильтрМассивДокументов = ОтобратьДокументыПоМоментамВремени(-1, МассивДокументов, ОпорныйДокументДляПроверки);
		ИскДокумент = КрайнийИзМоментовВремени(ФильтрМассивДокументов, +1);
	КонецЕсли;
	
	ИскСтрока = ТЗ.Найти(ИскДокумент, "Документ");
	Если ИскСтрока <> Неопределено Тогда
		ЗаполнитьЗначенияСвойств(Р, ИскСтрока);
	КонецЕсли;  

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

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

Функция КрайнийИзМоментовВремени(МассивДокументов, Направление, ОпорныйДокумент = Неопределено)
	//Направление 1 - вперед во времени, -1 назад во времени
	//Проверять дату опорного документа надо отдельно

	ЛучшийМомент = Неопределено;
	ЛучшийДокумент = Неопределено; 
	
	//Если есть опорный документ, его момент и считаем лучшим, остальные должны быть лучше его
	Если ОпорныйДокумент <> Неопределено Тогда
		ЛучшийМомент = ОпорныйДокумент.МоментВремени();
	КонецЕсли;
	
	Для Каждого Документ ИЗ МассивДокументов Цикл
		МоментВремени = Документ.МоментВремени();
		Если ЛучшийМомент = Неопределено Тогда
			ЛучшийМомент = МоментВремени;
			ЛучшийДокумент = Документ;
		Иначе                           
			Если Направление = 1 И МоментВремени.Сравнить(ЛучшийМомент) = 1 Тогда
				ЛучшийМомент = МоментВремени;
				ЛучшийДокумент = Документ;
			ИначеЕсли Направление = -1 И МоментВремени.Сравнить(ЛучшийМомент) = -1 Тогда
				ЛучшийМомент = МоментВремени;
				ЛучшийДокумент = Документ;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Возврат ЛучшийДокумент;
	
КонецФункции

Я потратил на этот код 4 часа и решил изменить функцию подсчета моментов. Упростить, избавиться от монструозности. Все же вернуться к запросам.

Если момент нельзя сравнить с параметром, его можно сравнить с другим моментом, полученным в запросе, подумал я.

Но слава богу, так сложно не потребовалось. Видимо, я споткнулся в начале на том, что граница была пустая и вместо момента времени передавал Неопределено.

Новую функцию получения соседнего документа написал минут за 20, быстро и заработало без проблем:

Функция ПолучитьСоседнийДокументГраницы(Направление, Организация, ОпорныйДокумент, Дата) Экспорт
	
	Р = Новый Структура("Документ, Дата", Неопределено, '00010101');
	//Направление = +1 Следующий, -1 предыдущий
	
	З = Новый Запрос(
	"ВЫБРАТЬ ПЕРВЫЕ 1
	|	Т.Период КАК Дата,
	|	Т.Регистратор КАК Документ
	|ИЗ
	|	РегистрНакопления.Запасы КАК Т
	|ГДЕ
	|	Т.Организация = &Организация
	|	И &Условие
	|
	|УПОРЯДОЧИТЬ ПО
	|	Дата УБЫВ" ); 
	
	ЕстьМомент = ОпорныйДокумент <> Неопределено;
	Если Направление = 1 Тогда
		Условие = "Т.Период > &Дата ИЛИ Т.Период = &Дата " + ?(ЕстьМомент, "И Т.МоментВремени > &Момент", "");
		Добавка = "Возр";
	Иначе
		Условие = "Т.Период < &Дата ИЛИ Т.Период = &Дата " + ?(ЕстьМомент, "И Т.МоментВремени < &Момент", "");;
		Добавка = "Убыв";              
	КонецЕсли;
	
	З.Текст = СтрЗаменить(З.Текст, "&Условие", "(" + Условие +")");
	З.Текст = СтрЗаменить(З.Текст, "УБЫВ", Добавка);
	
	З.УстановитьПараметр("Организация", Организация);
	З.УстановитьПараметр("Дата", Дата);             
	Если ЕстьМомент Тогда
		З.УстановитьПараметр("Момент", ОпорныйДокумент.МоментВремени());
	КонецЕсли;
	
	//Если момент найден, то возвращаем его
	Выборка = З.Выполнить().Выбрать();
	Если Выборка.Следующий() Тогда
		ЗаполнитьЗначенияСвойств(Р, Выборка);
	КонецЕсли;  

	Возврат Р;
	
КонецФункции


Всё гениальное действительно просто!

Среда: УНФ 3.0.8.91. Объем: 4.5 час

fixin

Программирую на 1С с 1999 года. В 1С просто Гений. В 2020 году ушел из офиса на вольные хлеба фриланса. Принимаю заказы.

Читайте также:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *