Почему не сохраняются записи в регистр сведений при записи нового элемента справочника в 1С:Бухгалтерия 3.0?

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

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

Разбор ситуации: программная запись в обработчике ПриЗаписи

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


Процедура ПриЗаписи(Отказ)
    Наим = СокрЛП(Наименование);
    Если Лев(Наим, 5) = "08.03" Тогда
        НаборЗаписей = РегистрыСведений.ПорядокОтраженияЗарплатыВБухУчете.СоздатьНаборЗаписей();
        НаборЗаписей.Отбор.СпособОтраженияЗарплатыВБухУчете.Установить(Ссылка);
        НаборЗаписей.Отбор.ЕНВД.Установить(Ложь);
        
        НоваяЗапись = НаборЗаписей.Добавить();
        НоваяЗапись.Счет = ПланыСчетов.Хозрасчетный.СтроительствоОбъектовОсновныхСредств;
        НоваяЗапись.СпособОтраженияЗарплатыВБухУчете = Ссылка;
        НоваяЗапись.ЕНВД = Ложь;
        
        НаборЗаписей.Записать();
    КонецЕсли;
КонецПроцедуры

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

Почему данные «пропадают»? Анализ работы управляемой формы

Проанализируем механику работы управляемых форм в типовых решениях. В конфигурации «Бухгалтерия предприятия 3.0» форма элемента справочника СпособыОтраженияЗарплатыВБухУчете — это не просто визуальное представление реквизитов объекта. Она активно управляет связанными данными. Данные регистра ПорядокОтраженияЗарплатыВБухУчете выведены на форму как отдельные реквизиты формы (не путать с реквизитами объекта!).

Разберем по шагам, что происходит, когда вы нажимаете кнопку «Записать и закрыть» для нового элемента:

  1. Форма инициирует запись объекта.
  2. В модуле объекта срабатывает ваш обработчик ПриЗаписи. В регистр успешно вносится запись.
  3. Транзакция записи объекта завершается.
  4. Внимание! Управляемая форма после успешной записи объекта выполняет свои постобработчики на сервере.
  5. Типовой код формы (например, в процедуре ПослеЗаписиНаСервере или через вызов общих модулей подсистемы «Зарплата и кадры») берет значения из своих реквизитов и принудительно записывает их в регистр.

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

Как решить проблему: три надежных способа

Рассмотрим варианты решения, которые позволят обойти «самодеятельность» типовой формы.

Способ 1: Использование программной записи вне контекста формы

Если ваша задача — массовое создание элементов или загрузка данных, делайте это программно, не открывая форму. При программном создании через Объект.Записать() обработчики формы не вызываются, и ваш код в ПриЗаписи модуля объекта отработает финально. Посмотрим на пример:


НовыйСпособ = Справочники.СпособыОтраженияЗарплатыВБухУчете.СоздатьЭлемент();
НовыйСпособ.Наименование = "08.03 Строительство";
// Заполняем другие реквизиты...
НовыйСпособ.Записать(); // Здесь ваш код в модуле объекта сработает корректно

Способ 2: Расширение формы (ПослеЗаписиНаСервере)

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

Алгоритм действий:

  1. Создаем расширение.
  2. Добавляем в него форму элемента справочника СпособыОтраженияЗарплатыВБухУчете.
  3. Создаем обработчик &После("ПослеЗаписиНаСервере").
  4. Переносим логику записи в регистр туда. В этот момент объект уже в базе, а форма закончила перезаписывать регистр.

Способ 3: Дополнительные свойства объекта

Проанализируем ситуацию, когда нам всё же нужно оставить код в модуле объекта. Мы можем передать из формы в модуль объекта «сигнал» о том, что запись инициирована интерактивно. Для этого используется коллекция ДополнительныеСвойства.

Однако в типовой БП 3.0 форма «не знает» о ваших намерениях. Можно попробовать реализовать обратную логику: в модуле объекта проверять наличие признака, который устанавливается только при программной записи. Если же признака нет — значит, пишет форма, и в этом случае можно позволить форме самой управлять регистром, предварительно заполнив реквизиты формы (если есть доступ к контексту).

Но наиболее архитектурно верным для БП 3.0 будет исследование типовой процедуры записи настроек отражения. Рассмотрим фрагмент кода, который часто управляет этим процессом в типовых формах:


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

Как мы видим, система проверяет заполненность реквизита Счет прямо на форме. Если вы хотите, чтобы запись сохранялась, вам нужно программно заполнить реквизиты формы до момента финальной записи. Это можно сделать в обработчике формы ПередЗаписьюНаСервере.

Резюме

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

← На главную