При работе с конфигурацией 1С:Управление торговлей (УТ) версии 11.4 часто возникает потребность в адаптации стандартных отчетов и печатных форм под специфические задачи бизнеса. Одной из таких задач может быть вывод розничных цен товаров в печатной форме документа «Поступление товаров», даже если сам документ изначально заполняется в закупочных ценах. Это особенно актуально, когда поступление товаров оформляется на конкретный магазин (склад), и нам требуется отобразить розничную цену, действующую именно для этого магазина. В данном руководстве мы подробно разберем, как реализовать такую внешнюю печатную форму.
Предположим, у нас есть несколько магазинов (например, «Маг1», «Маг2», «Маг3»), и для каждого из них могут быть установлены свои розничные цены. Наша цель – разработать внешнюю печатную форму, которая, будучи вызванной из документа «Поступление товаров», сможет определить розничную цену каждого товара, исходя из того, на какой склад (магазин) осуществляется поступление.
В системе 1С:УТ 11.4 информация о ценах на товары хранится в периодическом регистре сведений «Цены номенклатуры». Этот регистр содержит следующие ключевые измерения и ресурсы:
ВидЦены: Определяет тип цены (например, «Розничная», «Оптовая», «Закупочная»).Номенклатура: Ссылка на элемент справочника «Номенклатура».Характеристика: Если используется учет по характеристикам, здесь указывается конкретная характеристика номенклатуры.Цена: Собственно, сама цена товара.ЕдиницаИзмерения: Единица измерения, в которой установлена цена.Дата (период): Дата, с которой начинает действовать данная цена.Для того чтобы получить актуальную розничную цену на определенную дату, нам необходимо будет обращаться к этому регистру, учитывая ВидЦены, Номенклатуру, Характеристику и Дату документа.
Первым делом нам нужно выяснить, какой именно ВидЦены соответствует розничным ценам для того склада, на который производится поступление. В 1С:УТ 11.4 часто такая информация хранится непосредственно в справочнике «Склады (магазины)». Например, в объекте Склад может быть реквизит РозничныйВидЦены.
Для начала, давайте убедимся, что мы можем получить объект склада из документа поступления. Предположим, что в структуре ДанныеПечати (переменная, в которую передается информация о документе в печатную форму) уже содержится ссылка на документ, и мы можем обратиться к его реквизитам. Например, к реквизиту Склад.
Чтобы получить ВидЦены, связанный со складом, мы можем использовать следующую конструкцию:
ВидЦен = ДанныеПечати.Склад.РозничныйВидЦены;
Здесь ДанныеПечати.Склад представляет собой объект ссылки на элемент справочника «Склады (магазины)», а РозничныйВидЦены – это его реквизит, хранящий ссылку на соответствующий элемент справочника «Виды цен номенклатуры». Это позволит нам однозначно определить, какой именно вид цен мы будем искать в дальнейшем.
Для проверки правильности получения вида цен, мы можем временно вывести его наименование в печатной форме. Например, создав в макете отдельную область и заполнив ее параметрами:
ОбластьМакета = Макет.ПолучитьОбласть("ВидЦены");
СтруктураДанныхВидЦены = Новый Структура;
ВидЦен = ДанныеПечати.Склад.РозничныйВидЦены;
СтруктураДанныхВидЦены.Вставить("ВидЦены", ВидЦен.Наименование); // Выводим наименование для проверки
ОбластьМакета.Параметры.Заполнить(СтруктураДанныхВидЦены);
ТабличныйДокумент.Вывести(ОбластьМакета);
После успешной проверки, что наименование вида цены выводится корректно, мы можем переходить к получению самих цен.
Теперь, когда у нас есть информация о ВидеЦены, мы можем запросить актуальные розничные цены для каждой позиции документа «Поступление товаров». Для этого мы будем использовать метод ПолучитьПоследнее() периодического регистра сведений ЦеныНоменклатуры.
Давайте рассмотрим процесс по шагам:
Изначально у нас может возникнуть соблазн использовать метод ПолучитьПоследнее() следующим образом:
ЦенаРозничная = РегистрыСведений.ЦеныНоменклатуры.ПолучитьПоследнее(ТекущаяДата(), ДанныеПечати.Склад.РозничныйВидЦены);
При попытке выполнить такой код, мы неизбежно получим ошибку «Несоответствие типов (параметр номер '2')». Почему это происходит? Потому что метод ПолучитьПоследнее() ожидает в качестве второго параметра не просто ссылку на ВидЦены, а структуру с отборами по измерениям регистра. Это ключевой момент, который часто вызывает затруднения у новичков.
Обратившись к Синтакс-Помощнику (вызывается по Ctrl+F1 на выделенном имени метода), мы увидим, что второй параметр должен быть структурой, где ключами являются имена измерений регистра (например, «Номенклатура», «ВидЦены», «Характеристика»), а значениями – соответствующие ссылки или значения. Синтакс-Помощник — ваш лучший друг в мире 1С, он убережет вас от многих ошибок!
С учетом вышесказанного, нам необходимо сформировать структуру отбора. Для каждой строки табличной части документа поступления нам понадобятся Номенклатура и, если используется, Характеристика. Дата, на которую мы ищем цену, обычно соответствует дате документа поступления.
В цикле обхода строк табличной части документа поступления (предположим, что данные о товарах находятся в переменной ВыборкаПоТоварам), мы будем выполнять следующие действия:
Номенклатуру из текущей строки товара.Характеристику из текущей строки товара (если характеристики используются).ВидЦены.ПолучитьПоследнее(), передав ему дату и нашу структуру отбора.Рассмотрим пример кода:
// Предположим, что у нас есть цикл по товарам документа
// Например, ВыборкаПоТоварам получена из запроса к табличной части документа
Для Каждого СтрокаТовара Из ВыборкаПоТоварам Цикл
// 1. Формируем структуру отбора для получения цены
Отбор = Новый Структура;
Отбор.Вставить("Номенклатура", СтрокаТовара.Номенклатура);
// Важно: Если характеристики используются, добавляем их в отбор
Если СтрокаТовара.Характеристика <> Неопределено Тогда // Проверяем, существует ли характеристика
Отбор.Вставить("Характеристика", СтрокаТовара.Характеристика);
КонецЕсли;
Отбор.Вставить("ВидЦены", ДанныеПечати.Склад.РозничныйВидЦены); // Наш заранее определенный вид розничной цены
// 2. Получаем последнее значение из регистра сведений "Цены номенклатуры"
// ТекущаяДата() можно заменить на ДатаДокументаПоступления
СтруктураРесурсов = РегистрыСведений.ЦеныНоменклатуры.ПолучитьПоследнее(ТекущаяДата(), Отбор);
// 3. Извлекаем саму цену из полученной структуры ресурсов
// Метод ПолучитьПоследнее() возвращает структуру со всеми ресурсами регистра.
// Нам нужен конкретный ресурс "Цена".
ЦенаРозничная = 0; // Инициализируем на случай, если цена не найдена
Если СтруктураРесурсов <> Неопределено Тогда
ЦенаРозничная = СтруктураРесурсов.Цена;
КонецЕсли;
// 4. Теперь у нас есть розничная цена для текущего товара.
// Мы можем вывести ее в печатную форму.
// Например, если у нас есть область макета для строки таблицы "СтрокаТаблицы|Данные"
ОбластьДанных = Макет.ПолучитьОбласть("СтрокаТаблицы|Данные");
// Заполняем параметры области данными о товаре из текущей строки
ОбластьДанных.Параметры.Заполнить(СтрокаТовара);
// Создаем отдельную структуру для розничной цены и заполняем ею область
СтруктураДанныхЦенаРоз = Новый Структура;
СтруктураДанныхЦенаРоз.Вставить("ЦенаРозничная", ЦенаРозничная);
ОбластьДанных.Параметры.Заполнить(СтруктураДанныхЦенаРоз); // При этом существующие параметры не будут перезаписаны, если имена разные
// Присоединяем область к табличному документу
ТабличныйДокумент.Присоединить(ОбластьДанных);
КонецЦикла;
Важный момент: ПолучитьПоследнее() возвращает структуру, содержащую все ресурсы регистра. Поэтому, чтобы получить саму цену, нам нужно обратиться к полю Цена этой структуры: СтруктураРесурсов.Цена. Если цена не найдена (например, для товара не установлена розничная цена выбранного вида), ПолучитьПоследнее() вернет Неопределено, поэтому всегда следует проверять результат перед обращением к полям.
Хотя метод ПолучитьПоследнее() удобен для получения единичных значений, его многократный вызов в цикле по большому количеству строк документа может существенно замедлить формирование печатной формы. Это особенно заметно в документах с сотнями позиций.
Для повышения производительности, особенно при обработке большого количества товаров, рекомендуется использовать запросы к регистру сведений с использованием виртуальной таблицы «СрезПоследних». Этот подход позволяет получить все необходимые цены за один запрос к базе данных, что значительно эффективнее построчного обращения.
Товары документа.РегистрСведений.ЦеныНоменклатуры.СрезПоследних(). Эта таблица позволяет получить последние значения ресурсов регистра на указанную дату для заданных условий отбора.&ДатаДокумента) и отбор по ВидуЦены (наш &РозничныйВидЦены). Также важно связать товары из табличной части с товарами в регистре по полям Номенклатура и Характеристика.
// В модуле обработки внешней печатной формы
// Предположим, что у нас есть ссылка на документ в переменной ДокументСсылка
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПоступлениеТоваровТовары.НомерСтроки КАК НомерСтроки,
| ПоступлениеТоваровТовары.Номенклатура КАК Номенклатура,
| ПоступлениеТоваровТовары.Характеристика КАК Характеристика,
| ПоступлениеТоваровТовары.Количество КАК Количество,
| ПоступлениеТоваровТовары.ЕдиницаИзмерения КАК ЕдиницаИзмерения,
| ПоступлениеТоваровТовары.Цена КАК ЗакупочнаяЦена, // Обычная цена из документа
| ПоступлениеТоваровТовары.Сумма КАК ЗакупочнаяСумма,
| ЦеныНоменклатурыСрезПоследних.Цена КАК РозничнаяЦена
|ИЗ
| Документ.ПоступлениеТоваров.Товары КАК ПоступлениеТоваровТовары
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&ДатаДокумента,
| ВидЦены = &РозничныйВидЦены) КАК ЦеныНоменклатурыСрезПоследних
| ПО ПоступлениеТоваровТовары.Номенклатура = ЦеныНоменклатурыСрезПоследних.Номенклатура
| И ПоступлениеТоваровТовары.Характеристика = ЦеныНоменклатурыСрезПоследних.Характеристика
|ГДЕ
| ПоступлениеТоваровТовары.Ссылка = &СсылкаНаДокумент
|УПОРЯДОЧИТЬ ПО
| НомерСтроки";
// Устанавливаем параметры запроса
Запрос.УстановитьПараметр("ДатаДокумента", ДокументСсылка.Дата); // Дата, на которую нужны цены
Запрос.УстановитьПараметр("СсылкаНаДокумент", ДокументСсылка);
Запрос.УстановитьПараметр("РозничныйВидЦены", ДокументСсылка.Склад.РозничныйВидЦены); // Получаем вид цены со склада документа
// Выполняем запрос
ВыборкаПоТоварам = Запрос.Выполнить().Выбрать();
// Далее обходим выборку и выводим данные в макет
Пока ВыборкаПоТоварам.Следующий() Цикл
ОбластьДанных = Макет.ПолучитьОбласть("СтрокаТаблицы|Данные");
// Заполняем параметры области из выборки запроса
// Имена параметров в макете должны соответствовать именам полей выборки
ОбластьДанных.Параметры.Заполнить(ВыборкаПоТоварам);
ТабличныйДокумент.Присоединить(ОбластьДанных);
КонецЦикла;
Этот запрос позволит нам получить все необходимые данные, включая розничные цены, за одно обращение к базе данных. В результате ВыборкаПоТоварам будет содержать уже рассчитанные розничные цены для каждой строки товара, что значительно упрощает дальнейшую работу с макетом и повышает производительность.
Если в вашей конфигурации 1С:УТ 11.4 активно используется механизм характеристик номенклатуры, это означает, что цены могут устанавливаться не только для самой номенклатуры, но и для ее конкретных характеристик. Например, футболка "размер S" и "размер M" могут иметь разные розничные цены, даже если это одна и та же номенклатура.
При получении цен, как с помощью ПолучитьПоследнее(), так и с помощью запроса, критически важно правильно передавать или учитывать параметр Характеристика. В противном случае вы можете получить некорректную цену (например, общую цену для номенклатуры вместо цены для конкретной характеристики) или вовсе не найти цену, если она установлена только для характеристики.
Как мы видели в примерах кода, если Характеристика используется (т.е., поле СтрокаТовара.Характеристика не Неопределено), ее необходимо добавлять в структуру отбора для ПолучитьПоследнее() или в условие соединения/отбора запроса.
При получении цен всегда важно указывать корректную дату. Обычно это дата документа, для которого формируется печатная форма. Если в течение дня цены могут меняться (что бывает реже, но возможно в определенных бизнес-процессах), необходимо убедиться, что запрос или метод ПолучитьПоследнее() учитывает время, если это является критичным для бизнеса. По умолчанию, Дата в срезе последних и ПолучитьПоследнее() работает с датой-временем, поэтому указание ДокументСсылка.Дата (которое содержит время) обычно достаточно.
Как уже упоминалось, Синтакс-Помощник (вызывается по Ctrl+F1 на выделенном слове или методе в конфигураторе) — это незаменимый инструмент для любого разработчика 1С. Он предоставляет исчерпывающую информацию о синтаксисе методов, их параметрах, возвращаемых значениях и часто включает примеры использования. При возникновении ошибок типа «Несоответствие типов» или непонимании, какие параметры ожидает функция, Синтакс-Помощник должен быть первым местом, куда мы обращаемся.
Внешняя печатная форма в 1С обычно состоит из двух основных частей:
&Номенклатура, &ЦенаРозничная) соответствовали именам полей в выборке запроса или ключам в структурах, которые мы используем для заполнения.Правильное взаимодействие между модулем и макетом – залог корректно работающей печатной формы.
Таким образом, комбинируя знания о структуре данных 1С:УТ 11.4, умелое использование запросов к регистрам сведений и правильное применение методов работы с объектами, мы можем успешно реализовать вывод розничных цен на внешнюю печатную форму документа «Поступление товаров». Такой подход обеспечивает не только функциональность, но и оптимальную производительность вашей системы.