Как программно создать документ «Установка цен номенклатуры» и почему не заполняются строки?

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

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

Разбор ошибки: почему цикл «Для каждого» не работает для нового документа

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


СсылкаДок = Документы.УстановкаЦенНоменклатуры.СоздатьДокумент();
СсылкаДок.Дата = ТекущаяДата();
ТЧТовары = СсылкаДок.Товары;

// ОШИБКА: ТЧТовары в новом документе пуста!
Для каждого СтрокаДок из ТЧТовары Цикл 
    СтрокаДок = ТЧТовары.Добавить(); 
    // ... заполнение реквизитов ...
КонецЦикла;

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

Правильный алгоритм добавления строк в табличную часть

Рассмотрим, как правильно организовать процесс добавления номенклатуры и установки цен. Вместо цикла мы должны явно вызвать создание новой строки. Посмотрим на корректный пример кода:


// Создаем объект документа
ДокОбъект = Документы.УстановкаЦенНоменклатуры.СоздатьДокумент();
ДокОбъект.Дата = ТекущаяДата();

// Обращаемся к табличной части
НоваяСтрока = ДокОбъект.Товары.Добавить();

// Заполняем реквизиты строки
НоваяСтрока.Номенклатура = Справочники.Номенклатура.НайтиПоНаименованию("Товар");
НоваяСтрока.Цена = 99; // Обратите внимание: передаем ЧИСЛО
НоваяСтрока.Валюта = Справочники.Валюты.НайтиПоКоду("643"); // Рубли

В этом примере НоваяСтрока является объектом типа ДанныеФормыСтруктура (если работаем на форме) или СтрокаТабличнойЧасти (в серверном коде). Теперь все присвоенные значения гарантированно попадут в объект документа.

Типизация данных: почему нельзя передавать цену как строку

Проанализируем еще одну частую ошибку — использование кавычек при установке цены: СтрокаДок.Цена = "99". В языке 1С типизация реквизитов объектов метаданных жестко определена в конфигураторе. Если для поля «Цена» установлен тип Число, передача строки может привести к следующим последствиям:

  1. Неявное преобразование: Платформа попытается сама превратить "99" в 99. Если в строке окажутся лишние символы (пробелы, валюта), преобразование может вернуть 0.
  2. Ошибки проведения: Некоторые механизмы проведения документов (особенно в сложных конфигурациях вроде УТ 11 или ERP) проверяют типы данных в таблицах значений. Несоответствие типов может вызвать программный сбой.
  3. Проблемы с точностью: При записи строкового значения могут быть проигнорированы настройки точности (количество знаков после запятой), заданные в метаданных.

Совет: Всегда передавайте числовые значения как числа, а даты — как объекты типа Дата. Не полагайтесь на автоматическое приведение типов.

Методы записи и проведения документа

Когда документ заполнен, его необходимо сохранить в базе данных. Разберем разницу между записью и проведением. В коде автора встречалась странная конструкция: СтрокаДок.Записать(РежимЗаписиДокумента.Проведение). Это грубая ошибка, так как метод Записать() существует только у объекта документа целиком, но не у отдельной строки табличной части.

Рассмотрим правильный подход к записи с использованием обработки исключений:


Попытка
    // Пытаемся сразу провести документ
    ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);
    Сообщить("Документ успешно проведен: " + ДокОбъект.Ссылка);
Исключение
    // Если проведение не удалось, просто записываем (сохраняем черновик)
    ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
    Сообщить("Документ только записан. Причина: " + ОписаниеОшибки());
КонецПопытки;

Функция ОписаниеОшибки() крайне важна: она подскажет, какой именно обязательный реквизит вы забыли заполнить (например, «Статус», «Ответственный» или «Подразделение»).

Поиск ссылочных данных (Номенклатура, Склады, Валюты)

Использование метода НайтиПоНаименованию() в программном коде считается «плохим тоном» и потенциальным источником багов. Если пользователь переименует товар или тип цен в интерфейсе, ваш код перестанет работать.

Проанализируем альтернативы:

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

Особенности современных конфигураций (УТ 11, ERP 2.x)

Если вы работаете в современных решениях на платформе 8.3, структура документа УстановкаЦенНоменклатуры значительно сложнее, чем в старой «Управлении торговлей 10.3». В новых версиях данные цен часто распределены по нескольким табличным частям, где одна таблица хранит товары, а другая — виды цен и их значения, связанные через индексы.

В таких случаях рекомендуется использовать не прямое заполнение ТЧ объекта, а вызов программного интерфейса (API), который предоставляется разработчиками конфигурации (например, методы в модуле менеджера документа). Это гарантирует, что все скрытые реквизиты и связанные регистры будут заполнены корректно.

← На главную