Почему не записываются проводки в документ Операция при работе на сервере 1С

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

При разработке обработок по автоматическому формированию бухгалтерских операций программисты часто сталкиваются с ситуацией, когда в файловом варианте базы данных код отрабатывает безупречно, а в клиент-серверном варианте (SQL) проводки внутри документа не создаются или бесследно исчезают. Проанализируем типичную ситуацию на примере документа ОперацияБух в конфигурации Бухгалтерия предприятия 3.0 КОРП.

Разбор исходной проблемы и кода

Рассмотрим ситуацию: у нас есть внешняя обработка, которая читает данные из файла Excel и создает документы «Операция (бухгалтерский и налоговый учет)». В коде создания документа используется раздельный подход: сначала создается и записывается сам объект документа, а затем формируется НаборЗаписей регистра бухгалтерии с фильтром по этому документу. Давайте посмотрим на фрагмент кода, который приводит к ошибке:


ОперацияБух = Документы.ОперацияБух.СоздатьДокумент();
// ... заполнение реквизитов (Организация, Дата и т.д.)
ОперацияБух.Записать(); 

// Создание набора записей напрямую через менеджер регистра
НаборЗаписей = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(ОперацияБух.Ссылка);
НаборЗаписей.Записывать = Истина;

// Цикл добавления проводок
Для Каждого СтрокаДанных Из МассивПлатежей Цикл
    Движение = НаборЗаписей.Добавить();
    Движение.Регистратор = ОперацияБух.Ссылка;
    Движение.Период = ОперацияБух.Дата;
    // ... заполнение счетов и субконто
КонецЦикла;

НаборЗаписей.Записать(); // Запись проводок в базу

// Финальная запись документа для обновления суммы
ОперацияБух.СуммаОперации = ИтоговаяСумма;
ОперацияБух.Записать(РежимЗаписиДокумента.Запись); 

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

Почему это работает в файловой базе и не работает на сервере

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

Решение №1: Работа через коллекцию Движения объекта (рекомендуемое)

Чтобы избежать конфликтов записи, правильнее всего использовать встроенную коллекцию документа. В этом случае документ «знает» о своих проводках, и при итоговой записи они будут корректно сохранены одной транзакцией. Разберем этот алгоритм по шагам:

  1. Создаем объект документа через СоздатьДокумент().
  2. Заполняем шапку (Организация, Дата, Содержание).
  3. Вызываем Записать(), чтобы получить ссылку (необходимо для регистратора).
  4. Обращаемся к коллекции Движения.Хозрасчетный напрямую через объект.
  5. Устанавливаем флаг Записывать = Истина для этой коллекции.
  6. В цикле добавляем проводки в коллекцию.
  7. Выполняем итоговую запись объекта.

Посмотрим на пример правильного кода:


ОперацияОбъект = Документы.ОперацияБух.СоздатьДокумент();
ОперацияОбъект.Дата = ДатаПериода;
ОперацияОбъект.Организация = ВыбраннаяОрганизация;
ОперацияОбъект.Записать(); // Получаем ссылку

// Работаем с движениями внутри объекта
Проводки = ОперацияОбъект.Движения.Хозрасчетный;
Проводки.Записывать = Истина;

СуммаДокумента = 0;
Для Каждого Стр Из ДанныеФайла Цикл
    НоваяПроводка = Проводки.Добавить();
    НоваяПроводка.Регистратор = ОперацияОбъект.Ссылка;
    НоваяПроводка.Период = ОперацияОбъект.Дата;
    НоваяПроводка.Организация = ОперацияОбъект.Организация;
    
    НоваяПроводка.СчетДт = ПланыСчетов.Хозрасчетный.НайтиПоКоду("57.03");
    // Используем типовой механизм для заполнения субконто
    БухгалтерскийУчет.УстановитьСубконто(НоваяПроводка.СчетДт, НоваяПроводка.SubkontoДт, 1, Стр.Контрагент);
    
    НоваяПроводка.СчетКт = ПланыСчетов.Хозрасчетный.НайтиПоКоду("62.01");
    НоваяПроводка.Сумма = Стр.Сумма;
    СуммаДокумента = СуммаДокумента + Стр.Сумма;
КонецЦикла;

ОперацияОбъект.СуммаОперации = СуммаДокумента;
// Теперь эта запись сохранит и реквизиты, и проводки
ОперацияОбъект.Записать(РежимЗаписиДокумента.Запись);

Решение №2: Использование набора записей без повторной записи объекта

Если по каким-то причинам (например, из-за специфических расширений или сложной логики в модуле объекта) вам необходимо использовать РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей(), то критически важно не вызывать метод Записать() у объекта документа после того, как вы записали набор записей.

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

Важный момент: При таком подходе сумма документа в списке операций может отображаться как 0. Это происходит потому, что реквизит СуммаОперации хранится в самой таблице документов. Чтобы она обновилась без перезаписи документа, в типовых конфигурациях достаточно открыть документ и нажать «Записать», либо программно рассчитать сумму заранее и сохранить её в объекте до записи проводок.

Дополнительные факторы, влияющие на запись на сервере

Рассмотрим еще несколько причин, по которым проводки могут не появляться:

Рекомендации по отладке без конфигуратора

Если вам запрещают использовать отладчик на сервере, проанализируем альтернативные способы проверки:

  1. Журнал регистрации: Обязательно проверяйте его. При ошибках записи в SQL-базу там фиксируются отказы транзакций.
  2. Попытка...Исключение: Оборачивайте метод Записать() в блок обработки исключений и выводите ОписаниеОшибки() в текстовый файл на сервере или в сообщение пользователю.
  3. Временные таблицы: Если проводки пропадают, попробуйте после записи набора записей выполнить запрос к регистру бухгалтерии в этой же процедуре и вывести количество записей через Сообщить(). Если количество больше нуля, значит, запись прошла, но данные затираются позже.

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

← На главную