Программное создание и заполнение документов — одна из самых частых задач разработчика 1С. На первый взгляд может показаться, что достаточно просто присвоить значения нужным полям, как в обычном объекте. Однако, когда мы работаем с типовыми конфигурациями (такими как «Бухгалтерия предприятия 3.0», «ERP» или «УТ 11»), прямое присваивание часто приводит к ошибкам: суммы не сходятся, счета учета не подставляются, а логика проведения нарушается. Разберемся подробно, как делать это правильно, следуя стандартам разработки.
Рассмотрим ситуацию, описанную в теме: попытка напрямую записать значение в СуммаДокумента. В типовых решениях 1С реквизит СуммаДокумента обычно является агрегирующим (расчетным). Это означает, что его значение должно соответствовать итогу по табличным частям (например, по расшифровке платежа или списку товаров). Если мы просто напишем НовыйДок.СуммаДокумента = 111;, то при записи документа или его открытии в интерфейсе система может пересчитать итог на основании пустой табличной части и затереть наше значение нулем.
Проанализируем ситуацию: для корректного заполнения документа нам нужно не просто «вбросить» данные в поля, а инициализировать объект так, чтобы сработали все внутренние механизмы конфигурации. Выясним причину, по которой простое присвоение считается «плохим тоном».
Первым делом после создания объекта методом СоздатьДокумент(), необходимо вызвать метод Заполнить(). Этот метод инициализирует событие ОбработкаЗаполнения в модуле объекта документа. Именно там в типовых конфигурациях прописана логика подстановки значений по умолчанию: ответственного, организации, валюты и других системных параметров. Для реализации такой логики по шаблонам можно использовать универсальный механизм заполнения документов и справочников значениями по умолчанию.
Рассмотрим пример кода:
НовыйДок = Документы.ПоступлениеНаРасчетныйСчет.СоздатьДокумент();
// Инициализируем заполнение стандартными значениями
НовыйДок.Заполнить(Неопределено);
// Теперь можно устанавливать специфические параметры
НовыйДок.Дата = ТекущаяДата();
НовыйДок.Организация = Справочники.Организации.НайтиПоРеквизиту("ИНН", "7701234567");
Если мы создаем документ на основании другого объекта (например, «Поступление на расчетный счет» на основании «Счета на оплату»), в метод Заполнить() нужно передать ссылку на объект-основание. Это автоматически заполнит почти все реквизиты и табличные части согласно правилам, заложенным разработчиками конфигурации.
Чтобы реквизит СуммаДокумента заполнился корректно, нам нужно заполнить табличную часть, из которой эта сумма «собирается». В документе «Поступление на расчетный счет» это табличная часть РасшифровкаПлатежа. Посмотрим на пример, как правильно заполнять строки и обновлять итоги документа.
НоваяСтрока = НовыйДок.РасшифровкаПлатежа.Добавить();
НоваяСтрока.СуммаПлатежа = 111;
НоваяСтрока.СтатьяДДС = Справочники.СтатьиДвиженияДенежныхСредств.ОплатаОтПокупателя;
// Важно заполнить все корреспондирующие счета, если это требуется для БУ
НоваяСтрока.СчетУчетаРасчетов = ПланыСчетов.Хозрасчетный.РасчетыСПокупателями;
// Теперь вызываем процедуру пересчета суммы документа.
// В типовых конфигурациях БП это часто делается так:
СуммаИтого = НовыйДок.РасшифровкаПлатежа.Итог("СуммаПлатежа");
НовыйДок.СуммаДокумента = СуммаИтого;
Важный момент: в современных конфигурациях на базе БСП (Библиотеки стандартных подсистем) для пересчета налогов, сумм и валют существуют специальные экспортные процедуры в модулях менеджеров или общих модулях. Например, ОбщегоНазначенияБП.РассчитатьСуммуДокумента(ЭтотОбъект). Всегда полезно заглянуть в модуль объекта и посмотреть, какие процедуры вызываются в обработчике ПередЗаписью. Для быстрого поиска готовых процедур конфигурации можно использовать справочник методов Бухгалтерии предприятия 3.0.
Если нам нужно заполнить сразу много реквизитов из какого-то источника (например, из структуры параметров или другого объекта), использование ЗаполнитьЗначенияСвойств значительно упрощает код и делает его чище. Проанализируем, как это работает вместе со структурой.
ПараметрыЗаполнения = Новый Структура;
ПараметрыЗаполнения.Вставить("Контрагент", СсылкаНаКонтрагента);
ПараметрыЗаполнения.Вставить("ДоговорКонтрагента", СсылкаНаДоговор);
ПараметрыЗаполнения.Вставить("Комментарий", "Создано автоматически из внешней системы");
// Заполняем реквизиты документа из структуры
ЗаполнитьЗначенияСвойств(НовыйДок, ПараметрыЗаполнения);
Этот метод ищет совпадения имен ключей в структуре с именами реквизитов документа и копирует значения. Это избавляет от громоздких конструкций с множеством знаков равенства.
Когда пользователь в интерфейсе меняет «Контрагента», у него автоматически подставляется основной «Договор». При программном заполнении простое присваивание НовыйДок.Контрагент = ... не вызовет автоматическую подстановку договора. Нам нужно либо заполнить договор вручную, либо программно вызвать ту же логику, что работает на форме.
В типовых конфигурациях логика «ПриИзменении» часто выносится в модуль менеджера или общие модули, чтобы ее можно было вызвать с сервера без участия формы. Разберем по шагам, что нужно сделать:
ПродажиСервер.ПриИзмененииКонтрагента(НовыйДок)).Перед тем как применить метод Записать(), крайне рекомендуется убедиться, что документ заполнен корректно с точки зрения бизнес-логики. Для этого существует метод ПроверитьЗаполнение(). Если обязательные поля (например, счета учета) не заполнены, метод вернет Ложь и выведет сообщения об ошибках.
Рассмотрим финальный алгоритм правильного создания документа:
Попытка
НовыйДок = Документы.ПоступлениеНаРасчетныйСчет.СоздатьДокумент();
НовыйДок.Заполнить(Неопределено);
// Ручное заполнение
НовыйДок.Дата = ТекущаяДата();
НовыйДок.Организация = Справочники.Организации.НайтиПоНаименованию("Наша Компания");
// Заполнение через структуру для удобства
Данные = Новый Структура("Контрагент, СуммаДокумента", ВыбранныйПартнер, 50000);
ЗаполнитьЗначенияСвойств(НовыйДок, Данные);
// Обязательно проверяем, все ли заполнено
Если НовыйДок.ПроверитьЗаполнение() Тогда
НовыйДок.Записать(РежимЗаписиДокумента.Проведение);
Сообщить("Документ успешно создан и проведен: " + НовыйДок.Ссылка);
Иначе
Сообщить("Ошибка при проверке заполнения документа!");
КонецЕсли;
Исключение
Сообщить("Произошла ошибка при создании документа: " + ОписаниеОшибки());
КонецПопытки;
Подведем итог нашему разбору. Чтобы программное создание документа в 1С было надежным, придерживайтесь следующих правил:
НовыйДок.Заполнить() сразу после создания.ЗаполнитьЗначенияСвойств() для массового переноса данных.НовыйДок.ОбменДанными.Загрузка = Истина;, но помните, что это отключит большинство проверок и автоматических расчетов.Попытка ... Исключение при записи, чтобы обработать возможные конфликты блокировок или ошибки бизнес-логики.Соблюдение этих принципов позволит вам писать чистый, стабильный код, который не будет ломаться при обновлениях конфигурации или изменении учетной политики организации.