Почему пропадают движения регистра накопления при закрытии месяца и как это исправить?

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

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

Анализируем причину проблемы: форма против модуля объекта

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

Разберем по шагам, что происходит при закрытии месяца:

  1. Система инициирует автоматическое перепроведение документов для восстановления последовательностей и актуализации расчетов.
  2. Перепроведение выполняется на стороне сервера в фоновом задании. При этом контекст формы документа не создается.
  3. Процедуры модуля формы (такие как ПослеЗаписиНаСервере) игнорируются, так как они предназначены только для взаимодействия пользователя с интерфейсом.
  4. У документа в метаданных обычно включено свойство "Удаление движений: Удалять автоматически". Перед началом проведения система очищает старые записи регистра.
  5. Поскольку код записи в регистр в модуле объекта отсутствует, после очистки новые записи просто не создаются. В итоге регистр оказывается пустым.

Место кода — в модуле объекта

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

В расширении для документа (например, СписаниеСРасчетногоСчета) необходимо создать перехватчик метода проведения. Мы будем использовать аннотацию &После, чтобы не нарушать типовую логику проведения, а дополнять ее своей.

Правильная реализация записи в регистр через расширение

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


&После("ОбработкаПроведения")
Процедура Расш1_ОбработкаПроведенияПосле(Отказ, РежимПроведения)
    
    // Проверяем наше условие, нужно ли делать движения
    Если Не ЭтотОбъект.СозданоДвижение Тогда
        Возврат;
    КонецЕсли;

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

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

Почему это решение работает надежно?

Выясним преимущества такого подхода:

  1. Транзакционность: Движения записываются в рамках той же транзакции, что и сам документ. Если при записи документа произойдет сбой, движения не сохранятся, что исключает появление "мусора" в базе.
  2. Работа в фоне: При программном вызове метода ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение) система всегда обращается к модулю объекта. Это гарантирует сохранение данных при закрытии месяца.
  3. Автоматизация: Использование коллекции Движения позволяет 1С автоматически управлять набором записей. Вам не нужно вручную создавать НаборЗаписей и устанавливать отбор по регистратору.

Важные нюансы настройки метаданных в расширении

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

Типичные ошибки: использование "Прочитать()"

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

Заключение

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

← На главную