Игры с границами последовательности

Я реализовал для УТ 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.

fixin

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

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

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

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