Приветствуем вас, коллеги! Многие начинающие разработчики в 1С сталкиваются с трудностями при попытке получить данные, которые, на первый взгляд, должны храниться в справочниках, но на самом деле находятся в других объектах конфигурации. В этой статье мы подробно рассмотрим, как правильно получать цены на услуги в конфигурации "1С:Отель", используя программный код и язык запросов.
Наш читатель столкнулся с проблемой, когда он мог получить наименования услуг из справочника Services, но никак не мог достать их цены. Это распространенная ситуация, поскольку цены являются динамическими данными, зависящими от времени, типа цены и других факторов, и для их хранения в 1С используются специальные объекты — регистры сведений.
Прежде чем перейти к решению, давайте кратко разберем, как вообще устроено хранение данных в системе 1С. Это поможет нам лучше понять, почему цены находятся именно в регистре сведений, а не напрямую в справочнике.
Services хранит информацию об услугах.Итак, мы выяснили, что справочники хранят сами объекты (услуги), а регистры сведений хранят данные об их свойствах (цены), которые могут меняться со временем. Теперь давайте рассмотрим подробнее, как это реализовано в "1С:Отель".
Как и было предположено нашим читателем, цены на услуги в конфигурации "1С:Отель" хранятся в периодическом Регистре сведений "ServicePrices". Слово "периодический" означает, что этот регистр способен хранить историю изменения цен во времени. Каждая запись в нем имеет привязку к дате, начиная с которой установленная цена становится актуальной.
Типичная структура этого регистра включает:
Service: Это ссылка на элемент справочника "Services" (конкретная услуга). Именно это измерение связывает цену с нашей услугой.PriceType: Это ссылка на справочник "Типы цен" (например, "Базовый тариф", "Тариф выходного дня", "Корпоративный тариф"). Наличие этого измерения позволяет хранить несколько цен для одной и той же услуги, но для разных тарифов или типов цен.Price: Числовое значение самой цены.Currency: Ссылка на справочник "Валюты", указывающая, в какой валюте установлена цена.Ваш первоначальный код, который обращался к справочнику Services для получения цен, был некорректным, потому что справочник услуг не хранит цену напрямую. Он лишь является одним из "ключей" (измерений), по которому цена ищется в регистре сведений.
Запрос — это наиболее правильный, гибкий и производительный способ получения данных в 1С, особенно когда вам нужно получить информацию для нескольких элементов сразу, или когда данные хранятся в связанных объектах. Для получения актуальных на определенную дату цен из периодического регистра сведений мы будем использовать его специальную виртуальную таблицу СрезПоследних. Эта таблица позволяет на лету сформировать "срез" — то есть выбрать самые последние (актуальные) записи на указанную нами дату.
Давайте рассмотрим полный пример программного кода, который демонстрирует получение цен на услуги с помощью запроса:
// Массив, в котором будем хранить коды нужных нам услуг
КодыУслуг = Новый Массив;
КодыУслуг.Добавить("ДОПМBB");
КодыУслуг.Добавить("ДОПМHB");
КодыУслуг.Добавить("ДОПМFB");
КодыУслуг.Добавить("АРЗАЛ");
// Создаем объект Запрос
Запрос = Новый Запрос;
// Устанавливаем текст запроса
Запрос.Текст =
"ВЫБРАТЬ
| ЦеныУслугСрезПоследних.Service.Наименование КАК НаименованиеУслуги,
| ЦеныУслугСрезПоследних.Service.Код КАК КодУслуги,
| ЦеныУслугСрезПоследних.Price КАК Цена,
| ЦеныУслугСрезПоследних.Currency КАК Валюта
|ИЗ
| РегистрСведений.ServicePrices.СрезПоследних(&НаДату, Service.Код В (&КодыУслуг) И PriceType = &ТипЦен) КАК ЦеныУслугСрезПоследних";
// Устанавливаем параметры запроса. Это очень важный шаг,
// поскольку параметры делают запрос более гибким и безопасным.
Запрос.УстановитьПараметр("НаДату", ТекущаяДата()); // Получаем цены, актуальные на текущий момент
// Передаем массив кодов услуг для отбора.
// Условие "Service.Код В (&КодыУслуг)" позволяет выбрать цены только для указанных нами услуг.
Запрос.УстановитьПараметр("КодыУслуг", КодыУслуг);
// Важно: Укажите нужный вам Тип Цен. Обычно он хранится в справочнике "ТипыЦен".
// Если тип цен не важен или у вас его нет, вы можете убрать эту строку
// и условие "И PriceType = &ТипЦен" из текста запроса.
ТипЦенОбъект = Справочники.PriceTypes.НайтиПоНаименованию("Базовый тариф");
Если ТипЦенОбъект.Пустая() Тогда
Сообщить("Тип цен 'Базовый тариф' не найден. Проверьте данные в справочнике 'Типы цен'.");
Возврат; // Прерываем выполнение, если не можем найти тип цен
КонецЕсли;
Запрос.УстановитьПараметр("ТипЦен", ТипЦенОбъект);
// Выполняем запрос
РезультатЗапроса = Запрос.Выполнить();
// Проверяем, не пустой ли результат, и выводим полученные данные
Если РезультатЗапроса.Пустой() Тогда
Сообщить("Цены для указанных услуг на текущую дату и тип цен не найдены.");
Иначе
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Сообщение = "Услуга: " + Выборка.НаименованиеУслуги +
" (Код: " + Выборка.КодУслуги + "), " +
"Цена: " + Выборка.Цена +
" " + Выборка.Валюта;
Сообщить(Сообщение);
КонецЦикла;
КонецЕсли;
Давайте подробнее разберем каждый аспект этого запроса:
ВЫБРАТЬ ...: Здесь мы указываем, какие поля нам нужны из результата запроса. Мы получаем наименование и код услуги (через точку ЦеныУслугСрезПоследних.Service.Наименование, так как Service — это ссылка на справочник), саму цену и валюту.ИЗ РегистрСведений.ServicePrices.СрезПоследних(...): Это обращение к виртуальной таблице СрезПоследних регистра сведений ServicePrices. Эта таблица принимает два необязательных параметра:
&НаДату) — это дата, на которую нужно получить срез. Мы передаем ТекущаяДата(), чтобы получить актуальные цены на сейчас.Service.Код В (&КодыУслуг) И PriceType = &ТипЦен) — это условие для отбора записей внутри среза. Мы отбираем цены только для тех услуг, коды которых содержатся в нашем массиве КодыУслуг, и только для определенного типа цен.КАК ЦеныУслугСрезПоследних: Мы даем псевдоним нашей виртуальной таблице, чтобы удобнее к ней обращаться в тексте запроса.УстановитьПараметр): Использование параметров запроса (&НаДату, &КодыУслуг, &ТипЦен) позволяет нам передавать значения из кода 1С в текст запроса, что делает запрос универсальным и защищенным от SQL-инъекций.Выполнить, Выбрать, Пока Выборка.Следующий() Цикл): После выполнения запроса мы получаем объект РезультатЗапроса. Метод Выбрать() возвращает объект Выборка, по которому мы можем итерироваться, чтобы получить каждую найденную запись.Этот пример является наиболее полным и учитывает такую важную деталь, как тип цены, что является стандартной практикой в большинстве конфигураций 1С.
Если перед нами стоит задача получить цену только для одной конкретной услуги и на определенную дату, мы можем обойтись без написания полного текста запроса, используя специальные методы менеджера регистра сведений. Это может быть немного проще для понимания новичком, но менее производительно при работе с большим количеством данных.
Рассмотрим пример кода для этого способа:
// 1. Найдем нужную услугу по коду в справочнике "Services"
КодИскомойУслуги = "ДОПМBB";
УслугаОбъект = Справочники.Services.НайтиПоКоду(КодИскомойУслуги);
// Проверяем, найдена ли услуга. Это критически важный шаг для избежания ошибок.
Если УслугаОбъект.Пустая() Тогда
Сообщить("Услуга с кодом '" + КодИскомойУслуги + "' не найдена!");
Возврат; // Прерываем выполнение, если услуга не найдена
КонецЕсли;
// 2. Найдем нужный тип цен.
// Если у вас нет типов цен или он не важен, этот шаг можно пропустить,
// но тогда нужно будет убрать "PriceType" из структуры отбора.
НаименованиеТипаЦен = "Базовый тариф";
ТипЦенОбъект = Справочники.PriceTypes.НайтиПоНаименованию(НаименованиеТипаЦен);
Если ТипЦенОбъект.Пустая() Тогда
Сообщить("Тип цен '" + НаименованиеТипаЦен + "' не найден!");
Возврат; // Прерываем выполнение, если тип цен не найден
КонецЕсли;
// 3. Создаем структуру для отбора по измерениям регистра сведений.
// В эту структуру мы помещаем значения тех измерений, по которым хотим получить цену.
Отбор = Новый Структура;
Отбор.Вставить("Service", УслугаОбъект); // Отбор по услуге
Отбор.Вставить("PriceType", ТипЦенОбъект); // Отбор по типу цены
// 4. Получаем срез последних записей на текущую дату с указанным отбором.
// Метод ПолучитьПоследнее() возвращает Структуру с ресурсами регистра или Неопределено,
// если запись не найдена.
ДанныеЦены = РегистрыСведений.ServicePrices.ПолучитьПоследнее(ТекущаяДата(), Отбор);
// 5. Проверяем результат и выводим цену
Если ДанныеЦены = Неопределено Тогда
Сообщить("Цена для услуги '" + УслугаОбъект.Наименование + "' с типом цен '" + ТипЦенОбъект.Наименование + "' не установлена на текущую дату.");
Иначе
Сообщить("Цена: " + ДанныеЦены.Price + " " + ДанныеЦены.Currency);
КонецЕсли;
Разберем основные шаги этого метода:
Справочники.Services.НайтиПоКоду("ДОПМBB"): Сначала нам нужно получить ссылку на сам объект "Услуга" из справочника Services. Мы используем метод НайтиПоКоду, но можно также использовать НайтиПоНаименованию или просто получить ссылку другим способом.Справочники.PriceTypes.НайтиПоНаименованию("Базовый тариф"): Аналогично, получаем ссылку на нужный нам объект "Тип цены" из справочника PriceTypes.Новый Структура: Для формирования условий отбора в ПолучитьПоследнее мы используем объект Структура. В эту структуру мы вставляем пары "ключ-значение", где ключами являются имена измерений регистра ("Service", "PriceType"), а значениями — ссылки на соответствующие объекты.РегистрыСведений.ServicePrices.ПолучитьПоследнее(ТекущаяДата(), Отбор): Это ключевой метод. Он обращается к менеджеру регистра сведений ServicePrices и запрашивает самую последнюю (актуальную) запись на указанную дату (ТекущаяДата()) с учетом заданных в структуре условий отбора. Если запись найдена, метод возвращает Структуру, содержащую ресурсы регистра (Price, Currency). Если записи нет, возвращается Неопределено.Неопределено: Всегда необходимо проверять результат вызова ПолучитьПоследнее(), так как регистр может не содержать данных, соответствующих нашим условиям.Исходя из нашего анализа и рассмотренных примеров, мы можем сделать несколько важных выводов и дать рекомендации:
СрезПоследних, СрезПервых). Этот подход обеспечивает лучшую производительность и гибкость, особенно при обработке большого объема данных или необходимости получения информации для множества элементов.Service и PriceType). Именно они определяют уникальность записи и являются "ключами" для поиска нужных данных.ServicePrices.СрезПоследних без условий, чтобы убедиться, что данные в регистре вообще есть, а затем постепенно добавляйте нужные измерения и отборы.Надеемся, что это подробное руководство помогло вам разобраться, как получать цены на услуги в "1С:Отель", и дало четкое понимание принципов работы с регистрами сведений. Успехов в вашем программировании!