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