При выполнении процедуры свёртки информационной базы на платформе 1С:Предприятие типовые механизмы фиксируют остатки и актуальные срезы данных на выбранную дату. Нередко возникает ситуация: процедура свёртки завершена успешно, однако при попытке запустить штатное удаление помеченных объектов система блокирует удаление карточек номенклатуры. Причиной блокировки чаще всего становятся ссылки в периодическом регистре сведений ЦеныНоменклатуры, созданные документом Корректировка записей регистров (или Корректировка регистров).
В этой статье мы подробно разберем, почему типовая свёртка подтягивает неактуальные позиции, как устроен документ корректировки и какими способами можно быстро очистить движения регистра от ссылок на помеченные объекты.
Проанализируем работу штатных механизмов формирования остатков цен при свёртке. В стандартных обработках срез цен строится запросом к виртуальной таблице СрезПоследних регистра сведений на дату обрезки базы. В типовом запросе разработчики, как правило, не накладывают условие отсечения ГДЕ НЕ Номенклатура.ПометкаУдаления. В итоге любая позиция, для которой когда-либо была зарегистрирована цена, признается актуальной на дату среза и переносится в новый период.
Второй аспект проблемы — проектирование метаданных. В типовых конфигурациях у измерения Номенклатура регистра сведений ЦеныНоменклатуры флаг Ведущее намеренно снят. Это защищает историю цен от случайного каскадного удаления при удалении номенклатуры в рабочей базе. Но при свёртке это правило оборачивается трудностями: регистр сохраняет жесткую ссылку и не дает физически удалить элемент из базы.
Часто у специалистов возникает вопрос: если номенклатура попала в документ корректировки, нужно ли вручную открывать документ и перевыбирать строки? Разберем внутреннее устройство этого объекта.
Документ КорректировкаЗаписейРегистров не имеет собственных табличных частей, где хранились бы ссылки на номенклатуру. Он представляет собой пустую оболочку — технологический регистратор. Все отображаемые в его форме строки физически хранятся непосредственно в таблицах движений соответствующих регистров. Таким образом, как только запись удаляется из самого регистра сведений, она автоматически перестает существовать и в документе корректировки. Никаких «висячих» строк внутри документа не остается.
Посмотрим на базовый алгоритм, позволяющий исключить помеченные элементы из набора записей конкретного документа свёртки. Для этого создадим внешнюю обработку с реквизитом КорректировкаРегистров (тип ДокументСсылка.КорректировкаЗаписейРегистров).
Разберем пример простого перебора набора записей:
Процедура ОчиститьЦеныПомеченныхНажатие(Кнопка)
СписокДляУдаления = Новый Массив;
НаборЗаписей = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(ЭтотОбъект.КорректировкаРегистров);
НаборЗаписей.Прочитать();
Для Каждого Позиция Из НаборЗаписей Цикл
Если Позиция.Номенклатура.ПометкаУдаления Тогда
СписокДляУдаления.Добавить(Позиция);
КонецЕсли;
КонецЦикла;
Для Каждого УдаляемыйОбъект Из СписокДляУдаления Цикл
НаборЗаписей.Удалить(УдаляемыйОбъект);
КонецЦикла;
НаборЗаписей.Записать();
Сообщить("Очистка набора записей успешно завершена.");
КонецПроцедуры
В этом коде мы сначала считываем набор записей по отбору регистратора, определяем строки с помеченными на удаление элементами, удаляем их из коллекции набора и перезаписываем результат в базу.
Если после свёртки в регистре цен сформировались сотни тысяч записей, построчный перебор и вызов метода Удалить() в цикле могут выполняться крайне медленно и вызывать избыточные блокировки СУБД. В таких ситуациях рассмотрим более эффективный метод — выборку только «живых» записей с помощью запроса и последующую загрузку через НаборЗаписей.Загрузить().
Разберем по шагам оптимизированный сценарий:
Номенклатура.ПометкаУдаления = ЛОЖЬ.
Процедура ОчиститьЦеныБыстро(СсылкаНаДокумент)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Период,
| Регистратор,
| НомерСтроки,
| Активность,
| ВидЦены,
| Номенклатура,
| Характеристика,
| Цена,
| Валюта
|ИЗ
| РегистрСведений.ЦеныНоменклатуры КАК Цены
|ГДЕ
| Цены.Регистратор = &Регистратор
| И Цены.Номенклатура.ПометкаУдаления = ЛОЖЬ";
Запрос.УстановитьПараметр("Регистратор", СсылкаНаДокумент);
ТаблицаЖивыхЦен = Запрос.Выполнить().Выгрузить();
НаборЗаписей = РегистрыСведений.ЦеныНоменклатуры.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(СсылкаНаДокумент);
// Замещаем весь набор подготовленной таблицей без помеченных на удаление
НаборЗаписей.Загрузить(ТаблицаЖивыхЦен);
НаборЗаписей.Записать();
Сообщить("Регистр успешно перезаписан оптимизированным методом.");
КонецПроцедуры
Проблему проще предотвратить до запуска свёртки. Проанализируем возможности стандартного помощника свёртки информационной базы:
ЦеныНоменклатуры можно переключить режим на «Не обрабатывать» или «Очистить». Это актуально, если исторические срезы цен не требуются, а актуальный прайс-лист вносится новым документом установки цен.ГДЕ НЕ Номенклатура.ПометкаУдаления И НЕ Номенклатура.ЭтоГруппа.Если после очистки регистра ЦеныНоменклатуры номенклатура по-прежнему не удаляется штатным инструментом Удаление помеченных объектов, проверим сопутствующие регистры сведений, которые свёртка не очищает автоматически:
Штрихкоды (или ШтрихкодыНоменклатуры) — независимый регистр, где также сохраняются ссылки на удаляемые карточки.СоответствияОбъектовИнформационныхБаз — регистр планов обмена, фиксирующий соответствие GUID при синхронизации.НоменклатураПоставщиков (НоменклатураКонтрагентов) — привязка артикулов внешних партнеров.Для точного определения оставшихся «хвостов» используем метод платформы НайтиПоСсылкам() либо встроенный в форму удаления отчёт о связях объектов. В крайнем случае, если ссылки остаются в исторических закрытых регистрах, допустимо воспользоваться обработкой поиска и замены значений, объединив все помеченные элементы в один архивный служебный элемент (например, [АРХИВ] Списанная номенклатура).