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