Как исправить ошибку «Поле объекта не обнаружено (цена)» при программном создании документа «Установка цен номенклатуры» в 1С

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

При программной работе с документами в конфигурациях на обычных формах (таких как «Управление торговым предприятием для Украины», «Управление производственным предприятием», «Управление торговлей 10.3» и «Комплексная автоматизация 1.1») разработчики часто сталкиваются с неприятной ошибкой при попытке открыть программно созданный документ «Установка цен номенклатуры». Документ успешно записывается в базу данных без каких-либо предупреждений, однако при попытке интерактивного открытия пользователь видит системное сообщение об ошибке следующего вида:

{Документ.УстановкаЦенНоменклатуры.Форма.ФормаДокумента.Форма(596)}: Поле объекта не обнаружено (цена)

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

Выясняем причину: почему возникает ошибка?

Для того чтобы понять природу ошибки, нам необходимо проанализировать разницу между тем, как данные хранятся в базе данных 1С, и тем, как они визуально отображаются на форме документа.

В физических таблицах СУБД табличная часть Товары устроена строго вертикально. Каждая строка содержит одну позицию номенклатуры, один конкретный тип цены, саму цену, валюту и единицу измерения. Если мы устанавливаем для одного товара («Ноутбук») три разных типа цен («Закупочная», «Оптовая», «Розничная»), в табличной части Товары физически будут созданы три отдельные строки.

Однако пользователю неудобно работать с такой вертикальной структурой. Для облегчения восприятия разработчики типовых решений спроектировали интерфейс формы документа в виде двухмерной матрицы (горизонтальной таблицы):

  1. Строками в этой матрице на форме являются уникальные позиции номенклатуры.
  2. Колонками выступают выбранные типы цен (например, «Закупочная», «Розничная» и т. д.).

При открытии формы документа запускается встроенный алгоритм перестроения интерфейса. Он выполняет следующие шаги поочередно:

  1. Считывает данные из табличной части ТипыЦен текущего документа.
  2. Для каждого типа цен, найденного в этой табличной части, динамически создает на форме колонки с именами вида цена0, цена1, валюта0, валюта1 и так далее (где цифра в конце — это порядковый индекс типа цены).
  3. Затем система обходит физические строки табличной части Товары, сопоставляет их с динамически созданными колонками по значению реквизита ТипЦен и заполняет ячейки на форме.

Если мы создаем документ программно и заполняем только номенклатуру и цену в ТЧ Товары, игнорируя служебные реквизиты и табличную часть ТипыЦен, механизм сопоставления полностью ломается. Переменная НомерСоответствияТекущейКолонки в коде формы возвращает пустое значение или неопределено. В результате система пытается обратиться к реквизиту формы НоваяСтрока["цена"] вместо, например, НоваяСтрока["цена0"]. Так как базовой колонки с именем «цена» на динамической форме не существует, платформа генерирует критическую ошибку «Поле объекта не обнаружено».

Пошаговый алгоритм правильного программного заполнения

Чтобы документ корректно записывался в базу данных и без ошибок открывался в интерактивном режиме, нам необходимо строго соблюдать правила заполнения связанных реквизитов. Разберем по шагам, какие именно данные мы обязаны подготовить.

Шаг 1. Заполнение табличной части «ТипыЦен»

В документе обязательно должна быть заполнена табличная часть ТипыЦен. Мы должны добавить туда все типы цен, которые планируем устанавливать для товаров в рамках этого документа.

Шаг 2. Заполнение обязательного реквизита «ТипЦен» в строках ТЧ «Товары»

Для каждой строки, которую мы добавляем в ТЧ Товары, мы должны явно указать ссылку на соответствующий тип цены в поле ТипЦен. Это значение должно строго совпадать с одним из типов цен, добавленных на первом шаге в ТЧ ТипыЦен.

Шаг 3. Заполнение реквизита «ИндексСтрокиТаблицыЦен» в ТЧ «Товары»

Это важнейший служебный числовой реквизит, который отвечает за группировку строк при визуализации на форме. Индексация начинается с нуля. Если для одной номенклатуры мы устанавливаем несколько разных цен (например, Оптовую и Розничную), то у обеих строк в табличной части Товары должен быть записан одинаковый ИндексСтрокиТаблицыЦен. Это даст понять форме документа, что данные цены относятся к одной и той же строке товара на экране.

Пример корректного программного кода

Рассмотрим подробнее практический пример реализации кода на языке 1С. В данном примере мы будем программно создавать новый документ, заполнять один тип цен («Розничная») и корректно инициализировать все связанные служебные поля.


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

// 2. Определяем тип цен, который будем устанавливать
ТипЦенРозничная = Справочники.ТипыЦенНоменклатуры.НайтиПоНаименованию("Розничная");

Если ТипЦенРозничная.Пустая() Тогда
    ВызватьИсключение "Не найден тип цен ""Розничная"" в справочнике!";
КонецЕсли;

// Заполняем ТЧ "ТипыЦен" документа - это предотвратит ошибку отсутствия колонок на форме
СтрокаТипаЦен = НовДок.ТипыЦен.Добавить();
СтрокаТипаЦен.ТипЦен = ТипЦенРозничная;

// Извлекаем валюту по умолчанию для заполнения строк
ВалютаДокумента = ТипЦенРозничная.ВалютаЦены;

// 3. Выполняем запрос для получения номенклатуры и цен
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Номенклатура.Ссылка КАК Номенклатура,
    |	Номенклатура.ЕдиницаХраненияОстатков КАК ЕдиницаИзмерения,
    |	&Стоимость КАК Стоимость
    |ИЗ
    |	Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |	НЕ Номенклатура.ЭтоГруппа";

// В качестве примера передадим тестовую стоимость
Запрос.УстановитьПараметр("Стоимость", 150);

РезультатЗапроса = Запрос.Выполнить();

Если НЕ РезультатЗапроса.Пустой() Тогда
    
    ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
    ИндексТовара = 0; // Инициализируем индекс для группировки строк на форме
    
    Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
        
        // Добавляем новую строку в ТЧ "Товары"
        СтрокаТовары = НовДок.Товары.Добавить();
        СтрокаТовары.Номенклатура = ВыборкаДетальныеЗаписи.Номенклатура;
        
        // КРИТИЧЕСКИ ВАЖНО: Заполняем реквизиты связи и служебные поля
        СтрокаТовары.ТипЦен = ТипЦенРозничная;
        СтрокаТовары.ИндексСтрокиТаблицыЦен = ИндексТовара;
        
        // Заполняем ценовые и количественные параметры
        СтрокаТовары.Цена = ВыборкаДетальныеЗаписи.Стоимость;
        СтрокаТовары.Валюта = ВалютаДокумента;
        СтрокаТовары.ЕдиницаИзмерения = ВыборкаДетальныеЗаписи.ЕдиницаИзмерения;
        
        // Коэффициент единицы измерения (обычно равен 1 для базовой единицы)
        Если ЗначениеЗаполнено(СтрокаТовары.ЕдиницаИзмерения) Тогда
            СтрокаТовары.Коэффициент = СтрокаТовары.ЕдиницаИзмерения.Коэффициент;
        Иначе
            СтрокаТовары.Коэффициент = 1;
        КонецЕсли;
        
        // Увеличиваем индекс для каждой новой уникальной позиции номенклатуры
        ИндексТовара = ИндексТовара + 1;
        
    КонецЦикла;
    
    // 4. Записываем готовый документ в базу данных
    НовДок.Записать(РежимЗаписиДокумента.Запись);
    Сообщить("Документ успешно создан: " + НовДок.Ссылка);
    
КонецЕсли;

Сложный сценарий: заполнение нескольких типов цен в одном документе

Проанализируем более сложную ситуацию, когда в рамках одного документа нам требуется установить сразу несколько типов цен (например, «Закупочная» и «Розничная») для каждой позиции номенклатуры. В этом случае логика работы с переменной ИндексСтрокиТаблицыЦен усложняется.

Для правильного сопоставления мы должны использовать один и тот же индекс строки для всех типов цен, относящихся к одной номенклатурной позиции. Схема заполнения будет выглядеть следующим образом:

Разберем пример кода, реализующий группировку цен для нескольких типов:


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

// Заполняем ТЧ "ТипыЦен" двумя типами цен
ТипЗакупочная = Справочники.ТипыЦенНоменклатуры.НайтиПоНаименованию("Закупочная");
ТипРозничная = Справочники.ТипыЦенНоменклатуры.НайтиПоНаименованию("Розничная");

СтрокаТЦ1 = НовДок.ТипыЦен.Добавить();
СтрокаТЦ1.ТипЦен = ТипЗакупочная;

СтрокаТЦ2 = НовДок.ТипыЦен.Добавить();
СтрокаТЦ2.ТипЦен = ТипРозничная;

// Допустим, у нас есть выборка уникальных товаров
// Во внешнем цикле обходим товары, во внутреннем - заполняем цены
ИндексСтроки = 0;

Для Каждого СтрокаТовара Из ТаблицаТоваровИсточник Цикл
    
    // Добавляем строку для Закупочной цены
    НоваяСтрокаЗакуп = НовДок.Товары.Добавить();
    НоваяСтрокаЗакуп.Номенклатура = СтрокаТовара.Номенклатура;
    НоваяСтрокаЗакуп.ТипЦен = ТипЗакупочная;
    НоваяСтрокаЗакуп.ИндексСтрокиТаблицыЦен = ИндексСтроки;
    НоваяСтрокаЗакуп.Цена = СтрокаТовара.ЦенаЗакупочная;
    НоваяСтрокаЗакуп.Валюта = ТипЗакупочная.ВалютаЦены;
    НоваяСтрокаЗакуп.ЕдиницаИзмерения = СтрокаТовара.ЕдиницаИзмерения;
    НоваяСтрокаЗакуп.Коэффициент = СтрокаТовара.Коэффициент;
    
    // Добавляем строку для Розничной цены на тот же самый товар с тем же индексом!
    НоваяСтрокаРозница = НовДок.Товары.Добавить();
    НоваяСтрокаРозница.Номенклатура = СтрокаТовара.Номенклатура;
    НоваяСтрокаРозница.ТипЦен = ТипРозничная;
    НоваяСтрокаРозница.ИндексСтрокиТаблицыЦен = ИндексСтроки;
    НоваяСтрокаРозница.Цена = СтрокаТовара.ЦенаРозничная;
    НоваяСтрокаРозница.Валюта = ТипРозничная.ВалютаЦены;
    НоваяСтрокаРозница.ЕдиницаИзмерения = СтрокаТовара.ЕдиницаИзмерения;
    НоваяСтрокаРозница.Коэффициент = СтрокаТовара.Коэффициент;
    
    // Инкрементируем индекс только при переходе к следующему товару!
    ИндексСтроки = ИндексСтроки + 1;
    
КонецЦикла;

НовДок.Записать(РежимЗаписиДокумента.Запись);

Резюме и практические советы

Для успешной бесконфликтной работы с документом УстановкаЦенНоменклатуры в коде всегда придерживайтесь следующих правил:

  1. Никогда не оставляйте табличную часть ТипыЦен пустой при программном формировании документа.
  2. Для каждой строки ТЧ Товары в обязательном порядке указывайте реквизиты ТипЦен и ИндексСтрокиТаблицыЦен.
  3. Если вы сомневаетесь в корректности заполнения структуры документа, всегда используйте встроенный отладчик 1С. Поставьте точку останова в модуле формы документа в процедуре при открытии и проверьте, какие значения принимает переменная сопоставления колонок.

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

← На главную