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