Как быстро отображать статус комплектации и расхождения между поступлением товаров и приходным ордером в динамическом списке 1С?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

При автоматизации ордерной схемы складского учета часто возникает задача: в форме списка документов поступления или приходных складских ордеров необходимо визуально отображать статус комплектации. Нужно быстро понимать, оформлен ли фактически складской ордер под финансовый документ и полностью ли совпадают номенклатурные позиции и их количества в обоих документах (с учетом того, что один товар в поступлении на складе может дробиться на множество строк по серийным номерам).

Основная сложность заключается в производительности: если в запросе динамического списка соединять табличные части документов, выполнять группировки или подзапросы, производительность списка критически снизится при росте базы данных. Кроме того, пользователи могут изменить строки в финансовом поступлении уже после фактической приемки товара на складе. Разберем по шагам, какими способами можно реализовать быструю и надежную сверку составов документов.

Почему вычисления «на лету» в динамическом списке неэффективны

Проанализируем ограничения платформы 1С при работе с динамическими списками:

  1. Вложенные запросы и соединения с табличными частями. Наличие конструкций LEFT JOIN с табличными частями или подзапросов с GROUP BY лишает СУБД возможности применять прямое постраничное считывание порций данных. Это приводит к избыточным блокировкам и зависаниям при прокрутке списка.
  2. Обработчик ПриПолученииДанныхНаСервере. Вычисление расхождений программным кодом для каждой видимой порции строк создает постоянную нагрузку на сервер при каждом скроллинге. Кроме того, по расчетным колонкам невозможно быстро отобрать или отсортировать документы на стороне сервера.

Для сохранения максимального быстродействия динамического списка статус должен храниться в уже готовом виде (в регистре сведений или в реквизите шапки документа) и считываться простым запросом без дополнительных агрегаций.

Вариант 1. Использование регистра сведений и событийная модель обновления

Рассмотрим классический способ хранения состояния комплектации в отдельном регистре сведений. Создадим непериодический регистр сведений СтатусыКомплектацииПоступлений со структурой:

  1. Измерение: ДокументПоступления (тип: ДокументСсылка.ПоступлениеТоваровУслуг).
  2. Ресурсы: Статус (тип: ПеречислениеСсылка.СтатусыКомплектации: НеОформлен, Укомплектован, ЕстьРасхождения), ЕстьОрдер (тип: Булево).

Так как изменение состава номенклатуры в поступлении может произойти уже после ввода ордера, сверку необходимо запускать при любых изменениях обоих документов. Создадим подписку на события ПриЗаписи и ОбработкаУдаленияПроведения для документов ПоступлениеТоваровУслуг и ПриходныйОрдерНаТовары.

Посмотрим на пример серверной процедуры, которая выполняет сверку свернутых табличных частей и фиксирует статус:


Процедура АктуализироватьСтатусКомплектации(СсылкаНаПоступление) Экспорт

	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	Поступление.Номенклатура КАК Номенклатура,
		|	СУММА(Поступление.Количество) КАК Количество
		|ПОМЕСТИТЬ ВТ_Поступление
		|ИЗ
		|	Документ.ПоступлениеТоваровУслуг.Товары КАК Поступление
		|ГДЕ
		|	Поступление.Ссылка = &СсылкаНаПоступление
		|СГРУППИРОВАТЬ ПО
		|	Поступление.Номенклатура
		|;
		|
		|ВЫБРАТЬ
		|	Ордер.Номенклатура КАК Номенклатура,
		|	СУММА(Ордер.Количество) КАК Количество
		|ПОМЕСТИТЬ ВТ_Ордера
		|ИЗ
		|	Документ.ПриходныйОрдерНаТовары.Товары КАК Ордер
		|ГДЕ
		|	Ордер.Ссылка.ДокументОснование = &СсылкаНаПоступление
		|	И Ордер.Ссылка.Проведен
		|	И НЕ Ордер.Ссылка.ПометкаУдаления
		|СГРУППИРОВАТЬ ПО
		|	Ордер.Номенклатура
		|;
		|
		|ВЫБРАТЬ
		|	ЕСТЬNULL(ВТ_Поступление.Номенклатура, ВТ_Ордера.Номенклатура) КАК Номенклатура,
		|	ЕСТЬNULL(ВТ_Поступление.Количество, 0) КАК КоличествоПоступление,
		|	ЕСТЬNULL(ВТ_Ордера.Количество, 0) КАК КоличествоОрдер
		|ИЗ
		|	ВТ_Поступление КАК ВТ_Поступление
		|		ПОЛНОЕ СОЕДИНЕНИЕ ВТ_Ордера КАК ВТ_Ордера
		|		ПО ВТ_Поступление.Номенклатура = ВТ_Ордера.Номенклатура";

	Запрос.УстановитьПараметр("СсылкаНаПоступление", СсылкаНаПоступление);
	ТаблицаСверки = Запрос.Выполнить().Выгрузить();

	ЕстьОрдер = Ложь;
	ЕстьРасхождения = Ложь;

	Для Каждого Стр Из ТаблицаСверки Цикл
		Если Стр.КоличествоОрдер > 0 Тогда
			ЕстьОрдер = Истина;
		КонецЕсли;

		Если Стр.КоличествоПоступление <> Стр.КоличествоОрдер Тогда
			ЕстьРасхождения = Истина;
		КонецЕсли;
	КонецЦикла;

	Если Не ЕстьОрдер Тогда
		ТекущийСтатус = ПредопределенноеЗначение("Перечисление.СтатусыКомплектации.НеОформлен");
	ИначеЕсли ЕстьРасхождения Тогда
		ТекущийСтатус = ПредопределенноеЗначение("Перечисление.СтатусыКомплектации.ЕстьРасхождения");
	Иначе
		ТекущийСтатус = ПредопределенноеЗначение("Перечисление.СтатусыКомплектации.Укомплектован");
	КонецЕсли;

	МенеджерЗаписи = РегистрыСведений.СтатусыКомплектацииПоступлений.СоздатьМенеджерЗаписи();
	МенеджерЗаписи.ДокументПоступления = СсылкаНаПоступление;
	МенеджерЗаписи.Статус = ТекущийСтатус;
	МенеджерЗаписи.ЕстьОрдер = ЕстьОрдер;
	МенеджерЗаписи.Записать(Истина);

КонецПроцедуры

В динамическом списке документов достаточно соединить основную таблицу документа с физической таблицей регистра РегистрСведений.СтатусыКомплектацииПоступлений по первичному ключу (измерению ДокументПоступления), что обеспечивает максимальную скорость выборки.

Вариант 2. Метод сверки контрольных сумм и хешей (ХешированиеДанных)

Разберем альтернативный высокоскоростной вариант, когда требуется избежать сложных запросов на сверку строк. Мы можем формировать цифровую контрольную сумму состава номенклатуры и количества.

Для этого в платформе 1С предусмотрен встроенный объект ХешированиеДанных (с поддержкой алгоритмов MD5, SHA1, SHA256). Алгоритм работы строится следующим образом:

  1. Табличная часть документа сворачивается по полям номенклатуры и суммарного количества, после чего сортируется по уникальному идентификатору (УникальныйИдентификатор()) номенклатуры.
  2. Формируется строковый канонический слепок данных (например: ИД_Номенклатуры_1:Количество;ИД_Номенклатуры_2:Количество;).
  3. Объект ХешированиеДанных формирует строковый хеш от этой строки и записывает его в реквизит шапки документа (например, ХешСоставаТоваров).

Посмотрим на пример вычисления контрольного хеша:


Функция ПолучитьХешСостава(ТабличнаяЧастьТовары) Экспорт

	Таблица = ТабличнаяЧастьТовары.Выгрузить();
	Таблица.Свернуть("Номенклатура", "Количество");
	
	Таблица.Колонки.Добавить("ИДНоменклатуры", Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(36)));
	Для Каждого Стр Из Таблица Цикл
		Стр.ИДНоменклатуры = Строка(Стр.Номенклатура.УникальныйИдентификатор());
	КонецЦикла;
	
	Таблица.Сортировать("ИДНоменклатуры Возр");
	
	КаноническаяСтрока = "";
	Для Каждого Стр Из Таблица Цикл
		КаноническаяСтрока = КаноническаяСтрока + Стр.ИДНоменклатуры + ":" + Формат(Стр.Количество, "ЧЦ=15; ЧДЦ=3; ЧРД=.; ЧГ=0") + ";";
	КонецЦикла;
	
	Хешер = Новый ХешированиеДанных(ХешФункция.MD5);
	Хешер.Добавить(КаноническаяСтрока);
	
	Возврат СтрЗаменить(Строка(Хешер.ХешСумма), " ", "");

КонецФункции

В этом случае проверка на полное совпадение номенклатуры и объемов сводится к простому сравнению строк: Поступление.ХешСоставаТоваров = Ордер.ХешСоставаТоваров. Это работает мгновенно даже при наличии сотен строк в табличной части.

Вариант 3. Балансовый метод на регистрах накопления (типовой подход)

Проанализируем подход, реализованный в типовых конфигурациях (1С:ERP, 1С:Комплексная автоматизация, 1С:Управление торговлей). В них применяется регистр накопления остаточного типа (например, ТоварыКОформлениюПоступления):

  1. Измерения регистра: ДокументОснование (поступление), Номенклатура, Склад.
  2. Ресурс: Количество.
  3. Логика движений: Финансовый документ поступления при проведении делает движение вида Приход на заявленное количество. Приходный ордер делает движение вида Расход на фактически принятое складом количество.

Если по данному документу-основанию в остатках регистра сумма ресурсов равна 0, значит, документ полностью укомплектован. Если остаток положительный или отрицательный — есть расхождения или недовоз/перевоз. Для вывода флага в динамический список в момент проведения документа фиксируется признак наличия расхождений в регистре сведений, что позволяет спискам документов открываться без задержек.

← На главную