В процессе эксплуатации сложных систем на базе 1С, таких как Управление производственным предприятием (УПП 1.3), администраторы и разработчики часто сталкиваются с проблемами блокировок при выполнении регламентных операций. Одной из наиболее острых ситуаций является конфликт между процедурой проведения по партиям за прошлый период и действиями пользователей в текущем периоде. Когда пользователь пытается пометить документ на удаление или отменить его проведение, система накладывает блокировки, которые могут прервать многочасовой процесс закрытия месяца.
Проанализируем ситуацию: стандартных механизмов проверки даты проведения в модулях бывает недостаточно, так как пользователи могут воздействовать на документы через формы списков, структуру подчиненности или групповые обработки. Рассмотрим подробнее, как реализовать надежный запрет пометки на удаление при соблюдении определенных условий (например, при попадании документа в закрытый период или во время работы обработки проведения по партиям).
Прежде чем приступать к написанию кода, разберем возможности штатного функционала. В большинстве типовых конфигураций, включая УПП 1.3, существует механизм Даты запрета изменения. Этот инструмент работает на уровне системных событий записи объектов и является наиболее предпочтительным.
ПометкаУдаления (удобно настраивать изменение запрета по группам).Если же штатный механизм по каким-то причинам не подходит (например, требуется динамическое условие, зависящее от работы конкретной обработки в данный момент), перейдем к программным методам.
Выясним причину, почему добавление кода в каждый документ (как показано в сообщениях форума) считается плохой практикой. Это усложняет обновление конфигурации и увеличивает риск пропустить какой-то тип документа. Профессиональный подход заключается в создании одной Подписки на событие.
Разберем по шагам создание такой проверки:
ПодпискаНаСобытие.ДокументОбъект (можно выбрать конкретные типы документов: ОПзС, ТребованиеНакладная и т.д.).ПередЗаписью.Посмотрим на пример кода, который позволяет определить, что документ именно сейчас помечается на удаление:
Процедура ПроверитьЗапретПометкиНаУдаление(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
// Если это новый документ, проверка не нужна
Если Источник.ЭтоНовый() Тогда
Возврат;
КонецЕсли;
// Проверяем, изменилась ли пометка удаления
// Мы сравниваем текущее состояние объекта с данными в базе данных
Если Источник.ПометкаУдаления И Не Источник.Ссылка.ПометкаУдаления Тогда
// Проверяем условия запрета (например, роль или дату)
Если Не РольДоступна("ПолныеПрава") Тогда
// Здесь может быть ваша проверка даты запрета
ДатаЗапрета = Константы.ДатаЗапретаРедактирования.Получить();
Если Источник.Дата <= ДатаЗапрета Тогда
Сообщить("Запрещено помечать на удаление документы в закрытом периоде!");
Отказ = Истина;
Возврат;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Важный нюанс: Обращение к Источник.Ссылка внутри события ПередЗаписью позволяет получить состояние объекта до момента его изменения. Это критически важно для определения факта установки пометки.
Рассмотрим ситуацию, когда пользователь пытается пометить на удаление уже проведенный документ. В 1С это действие всегда инициирует отмену проведения. Следовательно, мы можем использовать модуль объекта самого документа.
Проанализируем пример кода в модуле объекта:
Процедура ОбработкаУдаленияПроведения(Отказ)
Если Не РольДоступна("ПолныеПрава") Тогда
// Проверяем условие, например, период проведения партий
Если ТекущаяДата() >= НачалоМесяца(Дата) И ТекущаяДата() <= КонецМесяца(Дата) Тогда
// Если период совпадает с выполняемой обработкой
Сообщить("В данный момент выполняется закрытие месяца. Удаление проведения запрещено.");
Отказ = Истина;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Этот метод хорош тем, что он срабатывает при попытке снять проведение из любого интерфейсного места: из формы документа, из списка или из окна Структура подчиненности. Однако помните, что он не сработает, если документ изначально не был проведен.
Для улучшения пользовательского опыта (UX) полезно пресекать действия еще до того, как они попадут в транзакцию записи базы данных. В обычных формах (как в УПП 1.3) для этого используется событие формы списка ПередУстановкойПометкиУдаления.
Рассмотрим пример реализации в форме списка документа ОтчетОПроизводствеЗаСмену:
Процедура СписокПередУстановкойПометкиУдаления(Элемент, Отказ)
ТекущаяСтрока = Элемент.ТекущиеДанные;
Если ТекущаяСтрока = Неопределено Тогда
Возврат;
КонецЕсли;
// Проверка условий запрета
Если ТекущаяСтрока.Дата <= Константы.ДатаЗапрета.Получить() Тогда
Предупреждение("Нельзя изменять пометку удаления для документов прошлых периодов!");
Отказ = Истина;
КонецЕсли;
КонецПроцедуры
Важное ограничение: Проверки в формах не являются абсолютной защитой. Они легко обходятся программными обработками или действиями в других связанных формах. Поэтому их следует использовать только как дополнение к методам в МодулеОбъекта или Подписках на события.
Если необходимо гарантировать запрет даже на уровне платформенных запросов и внешних инструментов, проанализируем возможность использования RLS. В ролях пользователей можно настроить ограничение на право «Изменение» для конкретных документов.
В условии RLS можно прописать текст запроса, который будет проверять дату документа. Платформа 1С на уровне ядра будет блокировать любые попытки записи (включая изменение пометки удаления), если дата документа попадает под условие ограничения. Это самый жесткий и надежный способ защиты данных от модификации.
Поскольку первопричиной задачи является длительное проведение по партиям и блокировки, разберем, как минимизировать эти конфликты архитектурно:
Истина, значит, запись идет в рамках обмена данными или специфической загрузки, и проверку часто стоит пропустить, чтобы не нарушить целостность распределенной базы.Подводя итог, наиболее сбалансированным решением для блокировки пометки на удаление является сочетание Подписки на событие «ПередЗаписью» (для надежности данных) и типового механизма дат запрета (для удобства администрирования).