Стоит ли изменять документ-основание напрямую при проведении подчиненного документа, и как это сделать правильно?

Программист 1С v8.3 (Управляемые формы)
← К списку

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

Решение 1: Использование регистров сведений (Рекомендуемый подход)

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

  1. Создание регистра сведений. Мы создаем новый регистр сведений, который будет хранить необходимые данные, связанные с Документом1, но формируемые Документом2. Этот регистр может быть как подчиненным регистратору (Документу2, если записи всегда связаны с его проведением), так и независимым (если данные могут быть изменены и другими способами). Для связи с Документом1 мы обязательно включаем в измерения регистра ссылку на Документ1.

  2. Заполнение регистра при проведении Документа2. В процедуре ОбработкаПроведения() модуля объекта Документа2 мы формируем движения по нашему новому регистру сведений. Здесь мы записываем все необходимые данные, которые должны быть "отражены" в Документе1.

    
    // Пример кода в модуле объекта Документа2, процедура ОбработкаПроведения()
    Движения.НашРегистрСведений.Записывать = Истина;
    Движение = Движения.НашРегистрСведений.Добавить();
    Движение.ДокументОснование = СсылкаНаДокумент1; // Из реквизита Документа2
    Движение.Период = Дата;
    Движение.Поле1 = ЭтотОбъект.РеквизитИзДокумента2_1;
    Движение.Поле2 = ЭтотОбъект.РеквизитИзДокумента2_2;
    // ... другие поля регистра
    
  3. Корректировка/очистка регистра при отмене проведения Документа2. Аналогично, в процедуре ОбработкаУдаленияПроведения() модуля объекта Документа2 мы должны предусмотреть удаление или корректировку записей в регистре сведений, которые были созданы при проведении. Система 1С автоматически отменяет движения, созданные в ОбработкаПроведения(), но если вы делали что-то специфичное, это нужно учесть.

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

    Например, мы можем добавить на форму Документа1 реквизит формы типа ДинамическийСписок, источником которого будет наш регистр сведений, и настроить отбор по текущему Документу1.

Преимущества использования регистров сведений:

Решение 2: Прямое изменение документа-основания (Не рекомендуемый, но возможный подход)

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

Основные шаги и особенности:

  1. Получение объекта документа-основания. В модуле объекта Документа2 (в процедурах ОбработкаПроведения() или ОбработкаУдаленияПроведения()) мы должны получить ссылку на Документ1 и затем прочитать его как объект:

    
    // Предположим, что ссылка на Документ1 хранится в реквизите Документа2
    СсылкаНаДокумент1 = ЭтотОбъект.ДокументОснование; 
    Документ1Объект = СсылкаНаДокумент1.ПолучитьОбъект();
    
  2. Блокировка документа-основания. Это критически важный шаг. Прежде чем изменять Документ1, мы должны его заблокировать, чтобы предотвратить одновременное изменение другими пользователями или процессами. Если Документ1 уже заблокирован, мы должны сообщить об этом пользователю и прервать проведение Документа2.

    
    Попытка
        Документ1Объект.Заблокировать();
    Исключение
        ТекстСообщения = СтрШаблон(
        НСтр("ru = '%1 находится в процессе редактирования пользователем или системой и не может быть изменена.';
        |en = '%1 is being edited by a user or the application and cannot be changed.'"),
        Документ1Объект.Ссылка);
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ТекстСообщения);
        Отказ = Истина; // Отменяем проведение Документа2
        Возврат;
    КонецПопытки;
    

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

  3. Изменение реквизитов и запись. После успешной блокировки мы можем изменить необходимые реквизиты Документа1Объект и записать его. Важно помнить, что все эти действия происходят в рамках одной транзакции, инициированной проведением Документа2. Если проведение Документа2 будет отменено, изменения в Документе1 также будут отменены.

    
    Документ1Объект.НашРеквизит = ЭтотОбъект.ЗначениеИзДокумента2;
    Документ1Объект.Записать();
    
  4. Обработка отмены проведения. В процедуре ОбработкаУдаленияПроведения() модуля объекта Документа2 мы должны предусмотреть обратные действия: получить Документ1, заблокировать его, вернуть реквизиты в исходное состояние (или в то состояние, которое было до проведения Документа2) и записать Документ1.

  5. Использование события ПриЗаписи(). Иногда для изменения связанных документов от записываемого документа-основания рекомендуется использовать событие ПриЗаписи(), чтобы не влиять на процедуру проведения документа. Однако, согласно методическим рекомендациям, в обработчике ПриЗаписи не рекомендуется изменять содержимое записываемого объекта. Если вы все же решите использовать его для изменения других документов, помните о необходимости блокировок и о том, что это происходит вне транзакции проведения, что может усложнить откат изменений.

Важные аспекты и дополнительные рекомендации

Независимо от выбранного подхода, нам необходимо учитывать несколько ключевых моментов, чтобы обеспечить стабильность и корректность работы системы.

  1. Управление блокировками данных. Мы уже коснулись этого, но давайте рассмотрим подробнее. При программном изменении существующих объектов крайне важно предварительно их заблокировать для редактирования. В 1С существуют два уровня блокировок: СУБД и 1С (управляемые блокировки). Метод Заблокировать() объекта метаданных ссылочного типа (Справочники, Документы) и метод глобального контекста ЗаблокироватьДанныеДляРедактирования() используются для установки блокировок. Управляемые блокировки позволяют нам блокировать данные более точно, что повышает параллельность работы. Всегда ставьте блокировку до записи и до чтения данных, чтобы избежать проблем с конкурентным доступом.

  2. Обновление форм. Если данные в Документе1 были изменены косвенно (например, через регистр сведений) или напрямую после действий с Документом2, открытую форму Документа1 может потребоваться обновить, чтобы пользователь увидел актуальную информацию. Мы можем обновить форму, получив ссылку на открытую форму и вызвав метод Прочитать() для обновления данных объекта формы или Обновить() для динамических списков. Для уведомления других форм об изменении данных мы можем использовать механизм оповещений.

  3. Связанные документы. В 1С существует механизм связанных документов, который позволяет системно объединять документы на основе определенных связей. Эти связи могут быть логическими или иерархическими. Хотя этот механизм не изменяет данные напрямую, он помогает отслеживать цепочки бизнес-операций и быстро переходить между документами, что может быть полезно для анализа изменений.

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

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

← К списку