Как связать документы в 1С и запретить редактирование документа-основания?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке конфигураций с нуля или доработке существующих баз часто возникает задача: необходимо связать несколько документов в логическую цепочку и сделать так, чтобы при наличии подчиненного документа (созданного на основании) исходный документ-основание нельзя было изменить. Давайте проанализируем эту задачу и разберем по шагам, как грамотно реализовать этот механизм в современных реалиях платформы 1С:Предприятие.

Ввод на основании и структура подчиненности: разбираем терминологию

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

  1. Ввод на основании — это исключительно механизм удобного заполнения одного документа данными другого документа. В момент, когда вы нажимаете кнопку «Создать на основании», платформа просто вызывает обработчик ОбработкаЗаполнения, передавая в него данные документа-основания. Сам по себе этот процесс не создает жесткой архитектурной связи в базе данных, если вы ее не сохраните.
  2. Подчиненность документов (связанные документы) — это фактическое наличие связи между объектами в базе данных через реквизиты ссылочного типа. Например, в документе «Реализация» есть реквизит ДокументОснование, в котором хранится ссылка на «Заказ клиента». Именно эта физическая ссылка формирует структуру подчиненности. Введенный на основании документ может и не иметь реквизита-ссылки, а подчиненный документ не обязательно должен создаваться именно через механизм ввода на основании.

Что такое «Критерии отбора» и почему мы их используем

Рассмотрим подробнее механизм платформы, который отвечает за поиск связанных ссылок. Это объект метаданных КритерииОтбора. Почему платформа использует именно его?

Представьте ситуацию: у нас есть документ «Счет на оплату». На его основании могут быть введены десятки других типов документов: «Реализация товаров», «Приходный кассовый ордер», «Счет-фактура выданный», «Возврат товаров» и так далее. Если бы критериев отбора не существовало, для построения дерева подчиненности нам пришлось бы писать гигантский запрос, объединяющий запросы ко всем возможным таблицам документов. Это крайне негативно сказалось бы на производительности.

Объект КритерийОтбора перекладывает эту задачу на уровень платформы и СУБД. Разработчику достаточно добавить нужные документы и их реквизиты в состав критерия, после чего платформа позволит мгновенно находить все связанные объекты, просто передав ссылку на искомый документ.

Настройка структуры подчиненности через БСП

В современных типовых конфигурациях (ERP, УТ, ЗУП, Бухгалтерия) никто не пишет структуру подчиненности с нуля. За это отвечает Библиотека стандартных подсистем (БСП). Посмотрим на алгоритм подключения новых документов к типовому дереву подчиненности:

  1. Откроем дерево метаданных и найдем объект КритерийОтбора.СвязанныеДокументы.
  2. На вкладке «Данные» необходимо указать типы ваших новых документов (тех, которые будут выступать основаниями и тех, которые будут ссылаться).
  3. На вкладке «Состав» отметим конкретные реквизиты новых документов (например, реквизит ДокументОснование), по которым система будет отслеживать связь.
  4. Затем найдем общую команду с именем СвязанныеДокументы и добавим наши документы в её тип параметра. После этого на форме документа автоматически появится типовая кнопка (иконка в виде дерева) для вызова отчета.

Важное примечание: Если мы работаем через Расширение конфигурации и не хотим снимать базу с поддержки, напрямую изменить состав критерия отбора не получится. В таком случае мы программно переопределяем БСП. Например, добавляем свой код в общий модуль СтруктураПодчиненностиСлужебный (в процедуру или функцию, отвечающую за индексы типов связанных объектов), чтобы алгоритмы БСП «увидели» наши новые реквизиты связи.

Реализация запрета редактирования документа-основания

Как мы уже выяснили, в самой платформе 1С нет магической галочки, которая автоматически запрещает редактирование документа при наличии подчиненных. Эту логику мы должны реализовать программно. Разберем по шагам два этапа блокировки.

1. Блокировка при записи документа

Это самый надежный рубеж защиты, который предотвратит изменение документа даже в том случае, если оно инициировано программно (например, при групповом перепроведении). Перейдем в модуль объекта нашего документа-основания и напишем следующий код в обработчике ПередЗаписью:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Пропускаем проверку при обмене данными
    Если ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;

    // Проверяем наличие связанных документов через критерий отбора
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |    СвязанныеДокументы.Ссылка КАК Ссылка
        |ИЗ
        |    КритерийОтбора.СвязанныеДокументы(&ТекущийДокумент) КАК СвязанныеДокументы
        |ГДЕ
        |    НЕ СвязанныеДокументы.Ссылка.ПометкаУдаления";
    
    Запрос.УстановитьПараметр("ТекущийДокумент", Ссылка);
    РезультатЗапроса = Запрос.Выполнить();
    
    Если Не РезультатЗапроса.Пустой() Тогда
        Отказ = Истина;
        Сообщить("Документ не может быть изменен! На его основании уже введены подчиненные документы.");
    КонецЕсли;

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

В этом коде мы обращаемся к виртуальной таблице КритерийОтбора.СвязанныеДокументы, передавая ссылку на текущий объект. Мы запрашиваем всего одну запись (ПЕРВЫЕ 1) и исключаем помеченные на удаление документы. Если запрос что-то вернул, устанавливаем параметр Отказ = Истина.

2. Блокировка пользовательского интерфейса (Формы)

Чтобы пользователю было комфортно работать, и он не сталкивался с ошибкой только в момент попытки сохранить документ, мы должны заблокировать форму документа еще при ее открытии. Для этого перейдем в модуль формы документа-основания.


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Блокируем форму, если документ уже записан и имеет подчиненные
    Если Не Объект.Ссылка.Пустая() Тогда
        Если ЕстьПодчиненныеДокументы(Объект.Ссылка) Тогда
            ЭтаФорма.ТолькоПросмотр = Истина;
        КонецЕсли;
    КонецЕсли;

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

&НаСервере
Функция ЕстьПодчиненныеДокументы(СсылкаНаДокумент)
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |    1 КАК Поле1
        |ИЗ
        |    КритерийОтбора.СвязанныеДокументы(&Ссылка) КАК СвязанныеДокументы
        |ГДЕ
        |    НЕ СвязанныеДокументы.Ссылка.ПометкаУдаления";
    
    Запрос.УстановитьПараметр("Ссылка", СсылкаНаДокумент);
    
    Возврат Не Запрос.Выполнить().Пустой();

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

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

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

← На главную