Как правильно изменить движения регистра накопления в подписке на событие ПередЗаписью?

Программист 1С v8.3 (Обычные формы) Управленческий учет Промышленность, строительство и АПК
← На главную

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

Разберем проблему: почему изменения «не подхватываются»?

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


Для Каждого Стр Из Источник Цикл
    Стр.Количество = 333;
КонецЦикла;

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

Опасность метода Прочитать() и причина дублирования записей

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

Выясним, почему это происходит. При проведении документа платформа работает в транзакции. Когда управление попадает в подписку ПередЗаписью, в базе данных (или в текущем транзакционном кэше) уже могут существовать записи, которые документ собирается заменить. Вызов Прочитать() загружает эти записи в коллекцию Источник. Затем платформа добавляет к этой коллекции новые записи, сформированные документом. В итоге при записи набора с параметром Замещение = Ложь (или при определенных условиях в транзакции) старые записи не удаляются, а новые записываются повторно. При каждом перепроведении количество записей будет увеличиваться вдвое, вчетверо и так далее.

Правильное решение: использование свойства Записывать

Чтобы изменения, внесенные в подписке, гарантированно попали в базу данных и при этом не возникло дублирования, необходимо использовать свойство Записывать объекта РегистрНакопленияНаборЗаписей. Рассмотрим корректный алгоритм действий:

  1. Проверяем, что набор записей не пустой (чтобы не выполнять лишних действий при очистке движений).
  2. Получаем ссылку на регистратор.
  3. Вносим необходимые правки в строки набора.
  4. Устанавливаем флаг Источник.Записывать = Истина.

Посмотрим на пример кода, который решает задачу подмены периода в регистре «Учет затрат» (РАУЗ) на основании реквизита документа:


Процедура ПередЗаписьюРНУчетЗатратПередЗаписью(Источник, Отказ, Замещение) Экспорт
    
    // Проверяем наличие записей, чтобы не обрабатывать пустые наборы
    Если Источник.Количество() > 0 Тогда
        
        РегистраторСсылка = Источник.Отбор.Регистратор.Значение; 
        
        // Проверяем тип документа, чтобы логика работала только для нужных объектов
        Если ТипЗнч(РегистраторСсылка) = Тип("ДокументСсылка.ПоступлениеТоваровУслуг") Тогда
            
            // Если в документе заполнена спец. дата, меняем период в движениях
            Если ЗначениеЗаполнено(RegisratorСсылка.ДатаЗатрат) Тогда 
                
                // Устанавливаем признак необходимости записи изменений
                Источник.Записывать = Истина;
                
                Для Каждого Стр Из Источник Цикл
                    Стр.Период = РегистраторСсылка.ДатаЗатрат; 
                КонецЦикла;
                
            КонецЕсли;
            
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

Важные нюансы и оптимизация

Проанализируем несколько важных моментов, которые помогут сделать ваш код более надежным и производительным:

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

2. Место установки флага Записывать. Как было замечено в обсуждении, строку Источник.Записывать = Истина лучше помещать непосредственно внутрь условия, где вы действительно меняете данные. Это предотвратит избыточные операции записи в случаях, когда модификация не требуется.

3. Специфика регистра «Учет затрат». В сложных конфигурациях, таких как УПП или Комплексная автоматизация 1.1, движения по регистру УчетЗатратРегламентированный могут формироваться не в самом документе, а в отдельных общих модулях механизма РАУЗ. Подписка на ПередЗаписью — это единственный надежный способ «поймать» эти движения, так как они могут записываться как независимый набор записей в обход стандартной коллекции Движения объекта-документа.

4. Взаимодействие с другими подписками. Если в вашей конфигурации создано несколько подписок на один и тот же регистр, они будут выполняться в порядке их расположения в дереве конфигурации. Убедитесь, что ваша логика не конфликтует с другими доработками. Помните, что флаг Записывать = Истина, установленный в одной подписке, повлияет на весь процесс записи набора.

Выводы

Мы выяснили, что для успешного редактирования движений в подписке на событие ПередЗаписью необходимо избегать метода Прочитать(), чтобы не вызвать дублирование данных. Вместо этого следует напрямую модифицировать коллекцию Источник и обязательно устанавливать свойство Источник.Записывать = Истина. Такой подход гарантирует целостность данных и корректную работу системы даже в сложных транзакционных механизмах, таких как учет затрат.

← На главную