При автоматизации бизнес-процессов в 1С нам очень часто приходится программно создавать различные документы — будь то загрузка данных из внешних систем, интеграция с банком или разработка собственных рабочих мест. Одной из частых проблем, с которой сталкиваются как начинающие, так и опытные разработчики, является автоматическое заполнение счетов учета (счетов расчетов, авансов и учета денежных средств).
Когда пользователь создает документ интерактивно в интерфейсе (на форме), система автоматически подставляет нужные счета учета при выборе организации, контрагента или договора. Но при программном создании документа эти счета часто остаются пустыми. В этой статье мы подробно разберем, почему попытка вызвать стандартные процедуры формы из кода приводит к ошибкам, и как правильно решить эту задачу с помощью штатных механизмов типовых конфигураций 1С.
Давайте разберем эту тему шаг за шагом, проанализируем причины типовых ошибок и напишем надежный, соответствующий стандартам разработки 1С код.
---
Рассмотрим ситуацию, в которую попал автор темы. Он попытался программно заполнить документ и, чтобы не прописывать счета учета вручную, решил вызвать процедуру, которая отрабатывает на форме при изменении организации:
ПоступлениеНаРасчетныйСчетФормы.ОрганизацияПриИзмененииСервер(ЭтотОбъект);
В результате система выдала ошибку: «Поле объекта не обнаружено (Организация)». Давайте разберемся, почему так произошло.
Дело в том, что в управляемом приложении 1С существует жесткое разделение между контекстом формы и контекстом объекта базы данных:
ДокументОбъект) — это сам документ со всеми его реквизитами и табличными частями, существующий в оперативной памяти сервера или записанный в базу. У него нет визуального отображения.УправляемаяФорма) — это визуальный интерфейс, с которым взаимодействует пользователь. Основным реквизитом формы является Объект (тип ДанныеФормыСтруктура), который временно хранит данные документа для отображения на экране.Экспортные процедуры во вспомогательных модулях с суффиксом Формы (например, ПоступлениеНаРасчетныйСчетФормы) разработаны исключительно для работы с контекстом формы. В качестве параметра они ожидают получить саму управляемую форму. Внутри такой процедуры код обычно обращается к данным вот так:
// Внутри общего модуля формы ожидает структуру формы:
ПараметрФорма.Объект.Организация
Когда разработчик программно создает документ через Документы.ПоступлениеНаРасчетныйСчет.СоздатьДокумент() и передает полученный объект в процедуру формы, система пытается прочитать свойство Поступление.Объект.Организация. Но у самого документа Поступление (который имеет тип ДокументОбъект) нет реквизита с именем Объект! У него реквизит Организация находится на самом верхнем уровне. Из-за этого несоответствия типов и возникает критическая ошибка «Поле объекта не обнаружено».
Пытаться вызывать клиентские или серверные методы формы из фонового задания или серверного модуля общего назначения — грубейшая архитектурная ошибка. Нам нужен другой, чисто серверный программный интерфейс.
---
В типовых конфигурациях «1С:Предприятие 8» (таких как «Бухгалтерия предприятия 3.0», «ERP Управление предприятием», «Комплексная автоматизация») вся бизнес-логика по определению счетов учета вынесена в специализированные общие модули. Нам не нужно изобретать велосипед или вручную копировать код из модулей форм.
Для заполнения счетов расчетов с контрагентами и счетов учета денежных средств предназначен общий серверный модуль СчетаУчетаВДокументах. Метод, который решит нашу задачу, называется Заполнить(). Он принимает объект документа, анализирует его реквизиты и автоматически заполняет все необходимые счета на основе правил, настроенных в регистре сведений «Счета учета расчетов с контрагентами».
Давайте посмотрим на пример правильного кода для программного создания и заполнения документа:
// Шаг 1. Создаем новый объект документа на сервере
НовыйДокумент = Документы.ПоступлениеНаРасчетныйСчет.СоздатьДокумент();
// Шаг 2. Заполняем основные реквизиты шапки
НовыйДокумент.Дата = ТекущаяДата();
НовыйДокумент.ВидОперации = Перечисления.ВидыОперацийПоступлениеДенежныхСредств.ОплатаПокупателя;
НовыйДокумент.Организация = Справочники.Организации.НайтиПоНаименованию("ПОУ");
// ВАЖНО: Счета расчетов зависят от контрагента и договора!
// Обязательно заполняем их перед вызовом подстановки счетов.
НовыйДокумент.Контрагент = Справочники.Контрагенты.НайтиПоРеквизиту("ИНН", "7701020304");
НовыйДокумент.ДоговорКонтрагента = Справочники.ДоговорыКонтрагентов.НайтиПоРеквизиту("Код", "00001", , НовыйДокумент.Контрагент);
// Заполняем банковский счет нашей организации
НовыйДокумент.СчетОрганизации = НовыйДокумент.Организация.ОсновнойБанковскийСчет;
// Шаг 3. Заполняем табличную часть (или Расшифровку платежа)
НоваяСтрока = НовыйДокумент.РасшифровкаПлатежа.Добавить();
НоваяСтрока.СпособПогашенияЗадолженности = Перечисления.СпособыПогашенияЗадолженности.Автоматически;
НоваяСтрока.СуммаПлатежа = 120000;
// Шаг 4. Подготавливаем параметры для автоматического заполнения счетов
// Создаем структуру отбора, чтобы указать, какие именно реквизиты нужно заполнять.
ПараметрыЗаполнения = Новый Структура;
// Истина — заполнить только пустые счета учета; Ложь — перезаписать даже ранее заполненные
ПараметрыЗаполнения.Вставить("НеЗаполненныеРеквизиты", Истина);
// Шаг 5. Вызываем универсальный механизм автозаполнения счетов
СчетаУчетаВДокументах.Заполнить(НовыйДокумент, ПараметрыЗаполнения);
// Шаг 6. Записываем готовый документ в базу данных
НовыйДокумент.Записать(РежимЗаписиДокумента.Запись);
---
Рассмотрим подробнее, что происходит внутри системы при вызове метода СчетаУчетаВДокументах.Заполнить(). Это знание поможет вам избежать ошибок при отладке.
Когда мы передаем объект нашего документа в эту процедуру, алгоритм платформы выполняет следующие действия:
ДокументСсылка.ПоступлениеНаРасчетныйСчет).Организация, Контрагент, ДоговорКонтрагента, а также валюту расчетов по договору.РегистрСведений.СчетаУчетаРасчетовСКонтрагентами. Этот регистр хранит правила подстановки счетов по приоритетам:
СчетРасчетов (например, 62.01) и СчетАвансов (например, 62.02).СчетОрганизации). Для рублевых счетов это обычно счет 51.---
Чтобы программное создание документа работало стабильно и без ошибок, рекомендуем обратить внимание на следующие технические аспекты:
Организация, Контрагент и ДоговорКонтрагента до вызова функции СчетаУчетаВДокументах.Заполнить(). Если эти поля будут пустыми, система просто не сможет найти правила подстановки счетов в регистре сведений, и счета останутся незаполненными.Попытка...Исключение, чтобы ошибка в одном документе не прерывала весь процесс импорта.Применяя этот подход, вы сохраняете целостность бизнес-логики типовой конфигурации. Если бухгалтер решит изменить счета учета расчетов с каким-то крупным контрагентом в пользовательском интерфейсе, ваш программный код автоматически начнет использовать новые настройки без необходимости переписывать сам программный код.