При переносе данных, выгрузке прайс-листов или формировании документов в конфигурации «Торговля и Склад 7.7» разработчики нередко сталкиваются с ситуацией, когда требуется программно получить розничную цену товара. Попытки обратиться к цене напрямую через реквизит номенклатуры вроде Номенклатура.Цена или через регистр остатков приводят к ошибкам либо возвращают нулевые значения. Проанализируем, как устроено хранение цен в платформе 1С:Предприятие 7.7, и разберем корректные способы программного извлечения розничных цен.
Для понимания логики работы системы рассмотрим внутреннюю структуру метаданных конфигурации «Торговля и Склад 7.7»:
Цены является подчиненным по отношению к справочнику Номенклатура. Каждый элемент справочника цен принадлежит конкретной позиции номенклатуры (владельцу) и ссылается на определенный тип цен через реквизит ТипЦен (ссылка на Справочник.ТипыЦен).Цена в справочнике Цены является периодическим. Это означает, что цена привязана ко времени (истории значений), и для ее чтения всегда необходимо указывать дату актуальности.ЦенаПрод (цена продажи) заполняется исключительно при движениях по складам с типом «Розничный». Если списание или остатки формируются по оптовому складу, учет ведется строго по себестоимости, и измерение ЦенаПрод всегда будет равно 0. Кроме того, в регистре фиксируется историческая стоимость партии, а не действующая цена из прайс-листа.Разберем классический алгоритм прямого обращения к объектам метаданных. Перед обходом строк необходимо один раз инициализировать объект типа цен и справочник цен, чтобы избежать лишнего создания COM-объектов в цикле. Внутри цикла установим владельца, найдем нужную запись по типу цен и запросим значение периодического реквизита на требуемую дату.
Посмотрим на пример реализации:
// 1. Инициализация объектов до начала цикла
РозничныйТипЦен = СоздатьОбъект("Справочник.ТипыЦен");
Если РозничныйТипЦен.НайтиПоНаименованию("Розничная", 0) = 0 Тогда
Если РозничныйТипЦен.НайтиПоНаименованию("Розничные", 0) = 0 Тогда
Сообщить("Тип цен не найден в справочнике!");
КонецЕсли;
КонецЕсли;
СпрЦены = СоздатьОбъект("Справочник.Цены");
ДатаАктуальности = ТекущаяДата(); // Либо ДатаДокумента
// 2. Обработка позиций внутри цикла
Пока РегистрыДокумента.ПолучитьДвижение() = 1 Цикл
// ... Пропуск лишних движений ...
Номенклатура = РегистрыДокумента.Номенклатура;
// Устанавливаем владельца для подчиненного справочника
СпрЦены.ИспользоватьВладельца(Номенклатура);
// Ищем цену с нужным типом (0 - поиск по всей длине реквизита)
Если СпрЦены.НайтиПоРеквизиту("ТипЦен", РозничныйТипЦен.ТекущийЭлемент(), 0) = 1 Тогда
// Получаем значение периодического реквизита на дату
Таблица.Цена = СпрЦены.Цена.Получить(ДатаАктуальности);
Иначе
Таблица.Цена = 0;
КонецЕсли;
КонецЦикла;
Альтернативный вариант работы с периодическим реквизитом — использование метода ИспользоватьДату():
СпрЦены.ИспользоватьВладельца(Номенклатура);
СпрЦены.ИспользоватьДату(ДатаАктуальности);
Если СпрЦены.НайтиПоРеквизиту("ТипЦен", РозничныйТипЦен.ТекущийЭлемент(), 0) = 1 Тогда
Таблица.Цена = СпрЦены.Цена; // Значение автоматически позиционировано на дату
КонецЕсли;
В типовой конфигурации «Торговля и Склад 7.7» реализован стандартный механизм для определения цен — глобальная функция глВернутьЦену. Использование этой функции предпочтительнее ручного поиска по нескольким причинам:
Рассмотрим синтаксис и практическое применение функции:
РозничныйТипЦен = СоздатьОбъект("Справочник.ТипыЦен");
РозничныйТипЦен.НайтиПоНаименованию("Розничная", 0);
ДатаЦены = ТекущаяДата();
// Переменные для приема возвращаемых значений
ЦенаВозврат = 0;
ЕдВозврат = 0;
ВалВозврат = 0;
// Вызываем штатную функцию
СтатусЦены = глВернутьЦену(Номенклатура, РозничныйТипЦен.ТекущийЭлемент(), ДатаЦены, ЦенаВозврат, ЕдВозврат, ВалВозврат);
Если СтатусЦены = 1 Тогда
Таблица.Цена = ЦенаВозврат;
ИначеЕсли СтатусЦены = -1 Тогда
// Цена помечена на удаление
Таблица.Цена = 0;
Иначе
// Цена не задана
Таблица.Цена = 0;
КонецЕсли;
При выгрузке цен в сторонние системы (например, в «1С:Розница 2.2») необходимо контролировать соответствие единиц измерения и валют:
Единица справочника Цены). Если в новую базу данные переносятся в базовых единицах (например, в штуках), а цена назначена за коробку из 10 штук, необходимо скорректировать цену: ЦенаЗаБазовую = ЦенаВозврат / ЕдВозврат.Коэффициент.Валюта в справочнике цен может иметь значение «USD» или «EUR». Если розничная цена ведется в валюте, перед передачей данных в документ розницы ее следует пересчитать в рубли по курсу на дату выгрузки через функцию глПересчет() или прямое чтение периодического реквизита Курс справочника Валюты.Если выгрузка остатков и цен охватывает десятки тысяч позиций номенклатуры, последовательный вызов методов НайтиПоРеквизиту и Получить внутри цикла существенно замедлит выполнение обработки из-за множественных обращений к таблицам базы данных (к файлам 1SCONST и SC* в файловом варианте или отдельным SQL-запросам в клиент-серверном).
Для ускорения процесса рекомендуется предварительно сформировать таблицу актуальных цен одним запросом к справочнику Цены с установленным фильтром по типу цен, либо выгрузить итоги периодических реквизитов во временную ТаблицаЗначений с последующим поиском через НайтиЗначение().