Игры с границами последовательности
Я реализовал для УТ 11.4 свой расчет средней себестоимости, корректирующий типовой отчет.
И после этого добрался до момента, когда нужно было следить за проведением документов задним числом с помощью границы последовательности.
Создал границу последовательности в разрезе организаций:
Осталось решить буквально нескольких вопросов. Обращался за подсказкой на Мисту, но там особо не помогли. Пришлось самому.
Установить границу последовательности
Установить границу на дату можно простым кодом:
ТекПоследовательность = Последовательности.дор_Себестоимость; ТекПоследовательность.УстановитьГраницу(ДатаГраницы, Новый Структура("Организация", Организация));
Получить границу последовательности можно кодом:
Последовательности.дор_Себестоимость.ПолучитьГраницу(Новый Структура("Организация", Организация))
Этот код возвращает последний структуру с документом границы последовательности, т.е. последним проведенным документом, на который встала граница последовательности:
Недостатки границы последовательности
Небольшой но важный нюанс — если граница последовательности только что создана, то пока она не установлена на какой-либо документ, она пустая. Даже если проводить документы, кроме
Еще более важный нюанс — если граница создана после того, как документы внесены в базу, то таблица границы не заполняется документам.
Проводим документ за 11 октября 2022 года. Граница устанавливается на этот документ, но таблица границы не изменяется, запрос выдает все те же данные с 19 октября 2022:
Проводим документ за 12 октября 2022 года. Граница не сдвигается на документ, потому что есть промежуточные документы. Это правильно. Но и таблица документов не заполняется.
Не знаю, как бороться с этим недостатком границы, поэтому я использовал запрос по регистру себестоимости для получения списков документов границы.
Восстановить границу последовательности
Алгоритм должен брать следующий документ в границе последовательности, запускать для него пересчет себестоимости и сдвигать границу на этот документ.
При этом нужно проверять в транзакции, что за время пересчета себестоимости граница не сдвинулась назад.
Все это выполняет вот этот код:
Процедура ВосстановитьСебестоимостьПоГраницеПоследовательности() Экспорт //Для проверки в консоли: _Сервер.ВосстановитьСебестоимостьПоГраницеПоследовательности() Организация = Справочники.Организации.ОрганизацияПоУмолчанию(); ТекПоследовательность = Последовательности.дор_Себестоимость; ПредДокумент = Неопределено; ПервыйДокумент = ТекПоследовательность.ПолучитьГраницу(Новый Структура("Организация", Организация)).Ссылка; Пока Истина Цикл СтруктураГраницы1 = Последовательности.дор_Себестоимость.ПолучитьГраницу(Новый Структура("Организация", Организация)); ТекДокумент = СледующийДокументГраницыПоследовательности(Организация); Если ТекДокумент = Неопределено ИЛИ ТекДокумент = ПредДокумент Тогда Прервать; КонецЕсли; ПредДокумент = ТекДокумент; дор_Себестоимость.РасчитатьСебестоимостьПоДокументу(ТекДокумент); //Чтобы в момент сдвига границы она не сдвинулась в другом месте НачатьТранзакцию(); СтруктураГраницы2 = Последовательности.дор_Себестоимость.ПолучитьГраницу(Новый Структура("Организация", Организация)); Если СтруктураГраницы1.Ссылка = СтруктураГраницы2.Ссылка И СтруктураГраницы1.Дата = СтруктураГраницы2.Дата Тогда ТекПоследовательность.УстановитьГраницу(ТекДокумент.МоментВремени(), Новый Структура("Организация", Организация)); ЗафиксироватьТранзакцию(); Иначе //Если граница поменялась пользователем ОтменитьТранзакцию(); Продолжить; КонецЕсли; КонецЦикла; //Если было восстановление Если ЗначениеЗаполнено(ПредДокумент) Тогда ЗаписьЖурналаРегистрации("Себестоимость.Граница",,ПервыйДокумент,, "Восстановлена граница с: " + ПервыйДокумент + " по: " + ПредДокумент); КонецЕсли; КонецПроцедуры Функция СледующийДокументГраницыПоследовательности(Организация) Экспорт СтруктураГраницы = Последовательности.дор_Себестоимость.ПолучитьГраницу(Новый Структура("Организация", Организация)); Если НЕ ЗначениеЗаполнено(СтруктураГраницы.Дата) Тогда Возврат Неопределено; КонецЕсли; З = Новый Запрос( "ВЫБРАТЬ ПЕРВЫЕ 1 | Т.Регистратор КАК Регистратор |ИЗ | РегистрНакопления.СебестоимостьТоваров КАК Т |ГДЕ | Т.Организация = &Организация | И &Условие | |УПОРЯДОЧИТЬ ПО | Т.Период, | Регистратор"); Если ЗначениеЗаполнено(СтруктураГраницы.Ссылка) Тогда //Если документ границы определен З.Текст = СтрЗаменить(З.Текст, "&Условие", "Т.Период >= &Период И Т.Регистратор.МоментВремени > &МоментВремени"); З.УстановитьПараметр("МоментВремени", Новый МоментВремени(СтруктураГраницы.Дата, СтруктураГраницы.Ссылка)); Иначе //Если документ не определен, только дата Ссылка = СтруктураГраницы.Ссылка; З.Текст = СтрЗаменить(З.Текст, "&Условие", "Т.Период >= &Период"); КонецЕсли; З.УстановитьПараметр("Период", СтруктураГраницы.Дата); З.УстановитьПараметр("Организация", Организация); Выборка = З.Выполнить().Выбрать(); Если Выборка.Следующий() Тогда Возврат Выборка.Регистратор; КонецЕсли; КонецФункции
Вот пример табло, который вслед за первым документом показывает следующий:
В конце в журнал регистрации заносится запись о восстановлении границы, например: Восстановлена граница с: Реализация товаров и услуг 00ЦБ-003269 от 20.10.2022 15:49:34 по: Чек ККМ 00ЦБ-007687 от 20.10.2022 17:36:39
Далее я этот код включил в регламентное задание и вызывал его каждый час, т.к. себестоимость у меня перерасчитывается быстро.
Важный момент по запросу — если просто сравнивать моменты времени, запрос работает долго, если добавить дату, то быстро. Я пытался сравнивать моменты времени сначала как дата + ссылка, но обнаружил, что запрос сравнивает по ссылке только документы одного типа, поэтому я получал не следующих документ в последовательности, а следующий документ такого же типа.
Среда: 8.3.17.2171.
Свежие комментарии