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