При разработке или правке отчетов в среде 1С:Предприятие 8, особенно в конфигурациях на обычных формах, таких как Управление торговлей 10.3, программисты часто сталкиваются с ошибками при попытке программного получения данных из регистров сведений. Одной из самых распространенных ошибок является Несоответствие типов (Параметр номер "1") при вызове метода ПолучитьПоследнее. В этой статье мы подробно разберем, почему возникает эта ошибка, как правильно получать цены и как корректно выводить их в макет отчета.
Проанализируем исходный код, который вызвал сбой:
РегистрыСведений.ЦеныНоменклатуры.ПолучитьПоследнее(отбор).Цена
Проблема кроется в синтаксисе метода. Согласно документации 1С, метод ПолучитьПоследнее для менеджера регистра сведений принимает два параметра:
Дата, МоментВремени или Граница) — это момент времени, на который мы хотим получить срез данных.Структура) — условия, по которым фильтруются записи (например, конкретная номенклатура и тип цены).В приведенном коде автор передал структуру отбор в качестве первого параметра. Система ожидает там дату, а получает объект типа Структура, что и приводит к ошибке «Несоответствие типов». Выясним, как это исправить.
Чтобы код заработал, нам нужно явно указать период. Если отчет должен показывать актуальные цены на текущий момент, мы передаем текущую дату. Если же мы хотим получить самую последнюю запись в базе вообще (без привязки к дате), мы можем оставить первый параметр пустым, но обязательно поставить запятую перед вторым.
Рассмотрим вариант получения цены на текущую дату:
Отбор = Новый Структура;
Отбор.Вставить("Номенклатура", СтрокаТЧ.Номенклатура);
Отбор.Вставить("ТипЦен", ТипЦен);
// Исправленный вариант с указанием текущей даты
ЦенаСтруктура = РегистрыСведений.ЦеныНоменклатуры.ПолучитьПоследнее(ТекущаяДата(), Отбор);
ЦенаЗаЕдиницу = ЦенаСтруктура.Цена;
Если же дата не имеет значения и нужно просто "самое последнее" значение, код будет выглядеть так:
// Обратите внимание на запятую перед переменной "Отбор"
ЦенаСтруктура = РегистрыСведений.ЦеныНоменклатуры.ПолучитьПоследнее(, Отбор);
Важно понимать, что метод ПолучитьПоследнее всегда возвращает объект типа Структура. Если в регистре нет записи, соответствующей вашему отбору, метод вернет пустую структуру. Попытка сразу обратиться к свойству .Цена в этом случае вызовет другую ошибку: «Поле объекта не обнаружено (Цена)».
Разберем, как написать надежный код, который не «вылетит» у пользователя, если цена на товар не установлена:
Отбор = Новый Структура;
Отбор.Вставить("Номенклатура", СтрокаТЧ.Номенклатура);
Отбор.Вставить("ТипЦен", ВыбранныйТипЦен);
ДанныеЦены = РегистрыСведений.ЦеныНоменклатуры.ПолучитьПоследнее(ТекущаяДата(), Отбор);
Если ДанныеЦены.Количество() > 0 Тогда
ЦенаЗначение = ДанныеЦены.Цена;
Иначе
ЦенаЗначение = 0; // Или другое значение по умолчанию
КонецЕсли;
Позиция.Параметры.Цена = ЦенаЗначение;
Позиция.Параметры.Сумма = ЦенаЗначение * СтрокаТЧ.Количество;
Часто возникает вопрос: почему в отчете выводится только общая сумма, а цена за единицу отсутствует? Проанализируем ситуацию. Чтобы данные появились в печатной форме, должны быть соблюдены два условия:
Рассмотрим по шагам, как добавить цену за единицу:
1. Откройте макет отчета в конфигураторе. Найдите строку, которая выводится в цикле (обычно она называется Детали или Строка). Найдите ячейку под заголовком "Цена".
2. Нажмите правой кнопкой мыши на ячейку — Свойства. В поле "Заполнение" выберите Параметр. В поле "Параметр" впишите имя, например, ЦенаЕд.
3. В коде обработки отчета добавьте заполнение этого параметра:
// Получаем цену (как мы разбирали выше)
ДанныеЦены = РегистрыСведений.ЦеныНоменклатуры.ПолучитьПоследнее(ТекущаяДата(), Отбор);
АктуальнаяЦена = ?(ДанныеЦены.Количество() > 0, ДанныеЦены.Цена, 0);
// Заполняем параметры области макета
Позиция.Параметры.ЦенаЕд = АктуальнаяЦена; // Теперь цена за 1 шт появится в макете
Позиция.Параметры.Сумма = АктуальнаяЦена * СтрокаТЧ.Количество;
Позиция.Параметры.Заполнить(СтрокаТЧ); // Заполняет остальные поля (Номенклатура, Количество и т.д.)
ТабДок.Вывести(Позиция);
Проанализируем подход, использованный в исходном сообщении. Использование метода ПолучитьПоследнее внутри цикла перебора строк табличной части (Для Каждого СтрокаТЧ Из...) является крайне неэффективным. Если в вашем отчете 1000 строк, система сделает 1000 отдельных запросов к базе данных. Это существенно замедлит работу программы.
Профессиональным стандартом в 1С 8.3 является использование Запроса. Мы рекомендуем использовать виртуальную таблицу СрезПоследних. Рассмотрим пример того, как получить все цены одним махом для всего документа или списка товаров:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЦеныНоменклатурыСрезПоследних.Цена КАК Цена,
| ЦеныНоменклатурыСрезПоследних.Номенклатура КАК Номенклатура
|ИЗ
| РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ТипЦен = &ТипЦен И Номенклатура В (&СписокНоменклатуры)) КАК ЦеныНоменклатурыСрезПоследних";
Запрос.УстановитьПараметр("Период", ТекущаяДата());
Запрос.УстановитьПараметр("ТипЦен", НужныйТипЦен);
Запрос.УстановитьПараметр("СписокНоменклатуры", ТабличнаяЧасть.ВыгрузитьКолонку("Номенклатура"));
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
// Теперь у вас есть таблица со всеми нужными ценами, которую можно быстро обработать
В конфигурации Управление торговлей 10.3 цена в регистре привязана к определенной единице измерения. Если вы продаете товар в "Коробках", а цена в регистре задана за "Штуки", простое умножение даст неверный результат.
Помните: при получении цены через ПолучитьПоследнее, структура также содержит поле Единица. Чтобы расчет был корректным, необходимо учитывать коэффициент этой единицы измерения по отношению к базовой единице номенклатуры. В типовых решениях для этого часто используются встроенные функции общих модулей, такие как Ценообразование.ПолучитьЦенуНоменклатуры(), которые автоматически учитывают и типы цен, и валюты, и единицы измерения.
Подводя итог, скажем: всегда проверяйте количество параметров в методах 1С и не забывайте о возможности возврата пустых значений. Это сделает ваш код надежным, а отчеты — точными.