В процессе сопровождения конфигураций «1С:Предприятие 8» (особенно таких как УТ 10.3, УПП 1.3 или сильно кастомизированных систем на обычных формах) часто возникает задача обеспечения целостности данных. Одной из критически важных задач является запрет редактирования ключевых реквизитов в справочнике ДоговорыКонтрагентов, если по этому договору уже проведены документы или зафиксированы движения в регистрах. Изменение организации или валюты в таком случае приведет к «развалу» партионного учета и неверным взаиморасчетам.
В этой статье мы подробно разберем, как реализовать механизм проверки наличия ссылок на договор и как правильно встроить его в логику работы системы. Мы рассмотрим несколько подходов: от использования стандартных критериев отбора до универсальных системных методов поиска ссылок.
Прежде чем переходить к написанию кода, выясним причину, по которой проверку следует размещать именно в определенном месте. Проанализируем два варианта:
ПередЗаписью в модуле объекта выполняется всегда, независимо от того, меняется договор вручную в форме или программно. Это гарантирует 100% защиту данных.Рекомендация: Лучше всего комбинировать оба подхода. В модуле формы в обработчике ПриОткрытии или ПриЧтенииНаСервере мы визуально блокируем поля, а в модуле объекта в процедуре ПередЗаписью выполняем финальную проверку перед записью в базу данных.
В типовых конфигурациях (например, УТ 10.3) часто уже предусмотрен критерий отбора ДокументыПоДоговоруКонтрагента. Это индексированный список, который позволяет быстро найти все документы, где выбран данный договор. Разберем пример кода, который можно вставить в модуль объекта:
Процедура ПередЗаписью(Отказ)
// Проверка осуществляется только если записывается уже существующий договор
Если НЕ ОбменДанными.Загрузка И НЕ ЭтоНовый() Тогда
// Проверяем, изменились ли критичные реквизиты
Если Организация <> Ссылка.Организация ИЛИ ВалютаВзаиморасчетов <> Ссылка.ВалютаВзаиморасчетов Тогда
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| ДокументыПоДоговору.Ссылка
|ИЗ
| КритерийОтбора.ДокументыПоДоговоруКонтрагента(&Договор) КАК ДокументыПоДоговору";
Запрос.УстановитьПараметр("Договор", Ссылка);
Результат = Запрос.Выполнить();
Если НЕ Результат.Пустой() Тогда
Сообщить("По договору уже оформлены документы. Изменение организации или валюты запрещено!", СтатусСообщения.Важное);
Отказ = Истина;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Обратите внимание на проверку ОбменДанными.Загрузка. Это критически важно: если данные загружаются из другой базы (например, при синхронизации), проверка не должна блокировать процесс, иначе обмен прервется с ошибкой.
Иногда договор может быть указан в документе, но документ не проведен (черновик). Если вы хотите запрещать редактирование только тогда, когда по договору прошли реальные движения в учете, лучше использовать запрос к ключевым регистрам. Рассмотрим пример функции, которая проверяет наличие записей в регистрах взаиморасчетов и продаж:
Функция СуществуютДвиженияПоДоговору(ДоговорСсылка)
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("ДоговорКонтрагента", ДоговорСсылка);
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1 ДоговорКонтрагента ИЗ РегистрНакопления.ВзаиморасчетыСКонтрагентами ГДЕ ДоговорКонтрагента = &ДоговорКонтрагента
|ОБЪЕДИНИТЬ ВСЕ
|ВЫБРАТЬ ПЕРВЫЕ 1 ДоговорКонтрагента ИЗ РегистрНакопления.РасчетыСКонтрагентами ГДЕ ДоговорКонтрагента = &ДоговорКонтрагента
|ОБЪЕДИНИТЬ ВСЕ
|ВЫБРАТЬ ПЕРВЫЕ 1 ДоговорКонтрагента ИЗ РегистрНакопления.Продажи ГДЕ ДоговорКонтрагента = &ДоговорКонтрагента";
Возврат НЕ Запрос.Выполнить().Пустой();
КонецФункции
Преимущества этого метода: Скорость. Запрос к конкретным таблицам регистров работает быстрее, чем поиск по всей базе. Вы сами определяете список регистров, которые считаются «критичными».
Если вы не знаете структуру регистров или конфигурация сильно доработана, можно воспользоваться системным методом НайтиПоСсылкам. Он находит вообще все упоминания объекта в любых таблицах базы данных (документах, справочниках, регистрах сведений).
МассивСсылок = Новый Массив;
МассивСсылок.Добавить(Ссылка);
ТаблицаСсылок = НайтиПоСсылкам(МассивСсылок);
Если ТаблицаСсылок.Количество() > 0 Тогда
// Объект где-то используется
Для Каждого СтрокаСсылок Из ТаблицаСсылок Цикл
Сообщить("На договор ссылается объект: " + СтрокаСсылок.Данные);
КонецЦикла;
Отказ = Истина;
КонецЕсли;
Проанализируем этот метод: несмотря на его универсальность, у него есть существенный недостаток. На больших базах данных выполнение НайтиПоСсылкам может занимать значительное время, так как платформа сканирует все таблицы. Используйте его с осторожностью в процедурах записи.
Выясним причину, по которой проверка может не сработать. Если у текущего пользователя ограничены права (например, настроены RLS — ограничения на уровне записей), запрос может не увидеть документы другого подразделения или организации. В результате пользователь сможет изменить договор, по которому «не видит» движений, что приведет к ошибке в учете.
Для корректной работы проверку нужно выносить в общий модуль с установленным флагом «Привилегированный». Это позволит системе выполнить поиск по всем таблицам базы данных, игнорируя ограничения прав доступа текущего пользователя.
В современных конфигурациях (на базе БСП) для решения этой задачи рекомендуется использовать подсистему «Запрет редактирования реквизитов объектов». В этом случае программисту не нужно писать сложные запросы. Достаточно зарегистрировать реквизит в соответствующей процедуре общего модуля (обычно это ПриОпределенииОбъектовСЗапретомРедактированияРеквизитов). После этого система сама заблокирует поле в форме и добавит кнопку «Разрешить редактирование», при нажатии на которую будет автоматически выполнен поиск ссылок.
Для надежного запрета изменения организации в договоре выполните следующие шаги:
ПередЗаписью в модуле объекта для контроля изменений.ОбменДанными.Загрузка, чтобы не блокировать интеграции.Критериям отбора или ключевым Регистрам накопления.Применяя эти методы, вы обеспечите стабильность системы и защитите данные от случайных некорректных правок.